摘要:特性支持過(guò)程式編程基于字節(jié)碼的代理重試基于注解的重試,允許自定義注解無(wú)縫接入接口與注解的統(tǒng)一解決與中的不足之處設(shè)計(jì)目的綜合了和的優(yōu)勢(shì)?;谧止?jié)碼實(shí)現(xiàn)的代理重試,可以不依賴。提供基于代碼模式字節(jié)碼增強(qiáng)實(shí)現(xiàn)的方式。
Sisyphus
支持過(guò)程式編程和注解編程的 java 重試框架。
特性支持 fluent 過(guò)程式編程
基于字節(jié)碼的代理重試
基于注解的重試,允許自定義注解
無(wú)縫接入 spring
接口與注解的統(tǒng)一
解決 spring-retry 與 guava-retrying 中的不足之處
設(shè)計(jì)目的綜合了 spring-retry 和 gauva-retrying 的優(yōu)勢(shì)。
調(diào)整一些特性,使其更利于實(shí)際使用。
采用 Netty 類(lèi)似的接口思想,保證接口的一致性,和替換的靈活性。
借鑒 Hibernate-Validator 的設(shè)計(jì),允許用戶自定義注解。
spring-retry 與 guava-retrying 中的不足之處更新記錄
更新記錄開(kāi)源地址
sisyphus快速開(kāi)始 引入
入門(mén)代碼com.github.houbb sisyphus-core 0.0.6
詳情參見(jiàn) [RetryerTest]()
public void helloTest() { Retryer.代碼分析newInstance() .retry(new Callable () { @Override public String call() throws Exception { System.out.println("called..."); throw new RuntimeException(); } }); }
retry
指定一個(gè) callable 的實(shí)現(xiàn)。
我們打印一條日志,并且模擬一個(gè)程序異常。
日志信息日志信息
called... called... called...
和一些其他異常信息。
重試觸發(fā)的條件,默認(rèn)是程序發(fā)生了異常
這里的重試間隔默認(rèn)為沒(méi)有時(shí)間間隔,一共嘗試3次。(包括第一次程序本身執(zhí)行)
為什么選擇 sisyphus 為什么選擇 sisyphus作為開(kāi)發(fā)者,我們一般都會(huì)選擇比較著名的框架。
比如 guava-retrying spring-retry。
或者干脆自己寫(xiě)一個(gè)。
為什么不是 guava-retrying/spring-retryjava retry 這篇文章中我列舉了常見(jiàn)的實(shí)現(xiàn)方式
以及上述的兩種框架,也講述了其中的不足。
使用靈活
fluent 優(yōu)雅寫(xiě)法
提供足夠多的實(shí)現(xiàn)
缺點(diǎn)沒(méi)有默認(rèn)基于注解的實(shí)現(xiàn)
重試策略設(shè)計(jì)并不友好
spring-retry 優(yōu)點(diǎn)使用簡(jiǎn)單
缺點(diǎn)重試條件單一
重試等待策略單一
無(wú)法自定義注解
為什么不自己寫(xiě)一個(gè) 個(gè)人感受我作為一名開(kāi)發(fā),平時(shí)說(shuō)實(shí)在的,看到重試。
我肯定會(huì)偷懶寫(xiě)一個(gè) for 循環(huán),重試幾次就結(jié)束了。
因?yàn)闀r(shí)間不允許。
如果你更勤快一點(diǎn),就可以選擇 spring-retry/guava-retrying。如果你熟悉他們的優(yōu)缺點(diǎn)的話。
如果你渴望創(chuàng)造sisyphus 所有的實(shí)現(xiàn)都是基于接口的。
你完全可以實(shí)現(xiàn)自己的實(shí)現(xiàn),所有的東西基本完全可以被替換。
當(dāng)然一些常見(jiàn)的策略實(shí)現(xiàn),項(xiàng)目的基本框架都有詳盡的注釋?zhuān)?dāng)做參考也可以有一點(diǎn)幫助。
sisyphus 做的更多的事情 netty 的靈感參考了 netty 的設(shè)計(jì),保證接口實(shí)現(xiàn)的一致性。
而且 sisyphus 還做了更多,還保證了接口和注解之間的一致性。
使用引導(dǎo)類(lèi),保證使用時(shí)的便利性,后期拓展的靈活性。
hibernate-validatorhibernate-validator 的作者是我知道為數(shù)不多的對(duì)于 java 注解應(yīng)用很棒的開(kāi)發(fā)者。(雖然所知甚少)
自定義注解就是從這個(gè)框架中學(xué)來(lái)的。
與 spring 為伍spring 基本與我們的代碼形影不離,所以你可以很簡(jiǎn)單的結(jié)合 spring.
就像你使用 spring-retry 一樣。
sisyphus 模塊簡(jiǎn)介 模塊劃分sisyphus 在模塊劃分的時(shí)候考慮到使用者的方便,主要有幾個(gè)模塊:
sisyphus-api接口定義模塊,是最基礎(chǔ)的部分。
會(huì)被 sisyphus-core 默認(rèn)依賴。
一般不需要引入,如果你想根據(jù)它實(shí)現(xiàn)自己的重試框架,不妨一試。
sisyphus-core對(duì)于 sisyphus-api 模塊的默認(rèn)實(shí)現(xiàn)。
并且添加易于使用的 Fluent 引導(dǎo)類(lèi),可以很方便的寫(xiě)出聲明式的重試代碼。
sisyphus-annotationsisyphus 的注解實(shí)現(xiàn)模塊。
(1)基于字節(jié)碼實(shí)現(xiàn)的代理重試,可以不依賴 spring。平時(shí)使用也更加靈活
(2)允許自定義注解及其實(shí)現(xiàn)。使用者可以編寫(xiě)屬于自己的重試注解。
sisyphus-springspring 做為 java 開(kāi)發(fā)的引導(dǎo)者。自然是要支持的。
你可以和使用 spring-retry 一樣方便的使用 sisyphus-spring。
模塊間的依賴關(guān)系sisyphus-api sisyphus-core sisyphus-annotation sisyphus-spring sisyphus-test
sisyphus-api 是基礎(chǔ)的,靈活性最高。
sisyphus-spring 是最簡(jiǎn)單易用的,靈活性相對(duì)較差。
sisyphus-test 僅僅用作測(cè)試,不用外部引入。
sisyphus 配置概覽為了滿足更加方便的配置,Retryer 類(lèi)提供了許多可以配置的信息。
默認(rèn)配置/** * 默認(rèn)配置測(cè)試 */ public void defaultConfigTest() { Retryer.newInstance() .condition(RetryConditions.hasExceptionCause()) .retryWaitContext(RetryWaiter. retryWait(NoRetryWait.class).context()) .maxAttempt(3) .listen(RetryListens.noListen()) .recover(Recovers.noRecover()) .callable(new Callable () { @Override public String call() throws Exception { System.out.println("called..."); throw new RuntimeException(); } }).retryCall(); }
和下面的代碼是等價(jià)的:
public void helloTest() { Retryer.方法說(shuō)明 conditionnewInstance() .callable(new Callable () { @Override public String call() throws Exception { System.out.println("called..."); throw new RuntimeException(); } }).retryCall(); }
重試觸發(fā)的條件,可以指定多個(gè)條件。
默認(rèn)為拋出異常。
retryWaitContext重試等待的策略,可以指定多個(gè)。
默認(rèn)為不做任何等待。
maxAttempt指定最大重試次數(shù),包括第一次執(zhí)行。
默認(rèn)值:3 次。
listen指定重試的監(jiān)聽(tīng)實(shí)現(xiàn),默認(rèn)為不做監(jiān)聽(tīng)。
recover當(dāng)重試完成之后,依然滿足重試條件,則可以指定恢復(fù)的策略。
默認(rèn)不做恢復(fù)。
callable待重試執(zhí)行的方法。
retryCall觸發(fā)重試執(zhí)行。
接口的詳細(xì)介紹 接口及其實(shí)現(xiàn)所有的接口,都可以直接查看對(duì)應(yīng)的子類(lèi)實(shí)例。
用戶自定義基于替換的靈活性,用戶可以實(shí)現(xiàn)接口,定義更符合自己業(yè)務(wù)的實(shí)現(xiàn)。
sisyphus 注解配置具有很高的靈活性,但是對(duì)于開(kāi)發(fā)人員的使用,就沒(méi)有注解那樣簡(jiǎn)單靈活。
所以本框架也實(shí)現(xiàn)了基于注解的重試。
設(shè)計(jì)的規(guī)范保證接口和注解二者的統(tǒng)一性。
maven 引入注解${project.groupId} sisyphus-annotation ${project.version}
核心注解主要有兩個(gè)。
Retry用于指定重試的相關(guān)配置。
/** * 重試注解 * 1. 實(shí)際需要,只允許放在方法上。 * 2. 如果放在接口上,是否所有的子類(lèi)都生效?為了簡(jiǎn)單明確,不提供這種實(shí)現(xiàn)。 * 3. 保持注解和接口的一致性。{@link com.github.houbb.sisyphus.api.core.Retry} 接口 * @author binbin.hou * @since 0.0.3 */ @Documented @Inherited @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @RetryAble(DefaultRetryAbleHandler.class) public @interface Retry { /** * 重試類(lèi)實(shí)現(xiàn) * @return 重試 * @since 0.0.5 */ Class extends com.github.houbb.sisyphus.api.core.Retry> retry() default DefaultRetry.class; /** * 最大嘗試次數(shù) * 1. 包含方法第一次正常執(zhí)行的次數(shù) * @return 次數(shù) */ int maxAttempt() default 3; /** * 重試觸發(fā)的場(chǎng)景 * @return 重試觸發(fā)的場(chǎng)景 */ Class extends RetryCondition> condition() default ExceptionCauseRetryCondition.class; /** * 監(jiān)聽(tīng)器 * 1. 默認(rèn)不進(jìn)行監(jiān)聽(tīng) * @return 監(jiān)聽(tīng)器 */ Class extends RetryListen> listen() default NoRetryListen.class; /** * 恢復(fù)操作 * 1. 默認(rèn)不進(jìn)行任何恢復(fù)操作 * @return 恢復(fù)操作對(duì)應(yīng)的類(lèi) */ Class extends Recover> recover() default NoRecover.class; /** * 等待策略 * 1. 支持指定多個(gè),如果不指定,則不進(jìn)行任何等待, * @return 等待策略 */ RetryWait[] waits() default {}; }RetryWait
用于指定重試的等待策略。
package com.github.houbb.sisyphus.annotation.annotation; import com.github.houbb.sisyphus.annotation.annotation.metadata.RetryWaitAble; import com.github.houbb.sisyphus.annotation.handler.impl.DefaultRetryWaitAbleHandler; import com.github.houbb.sisyphus.core.constant.RetryWaitConst; import com.github.houbb.sisyphus.core.support.wait.NoRetryWait; import java.lang.annotation.*; /** * 重試等待策略 * 1. 為了對(duì)應(yīng)重試策略,所有的內(nèi)置注解應(yīng)該實(shí)現(xiàn)當(dāng)前的注解。 * 2. 是否允許自定義注解? * * 當(dāng)注解+對(duì)象同時(shí)出現(xiàn)的時(shí)候,視為組合。 * * @author binbin.hou * @since 0.0.3 */ @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @Target(ElementType.ANNOTATION_TYPE) @RetryWaitAble(DefaultRetryWaitAbleHandler.class) public @interface RetryWait { /** * 默認(rèn)值 * 1. fixed 模式,則對(duì)應(yīng)固定等待時(shí)間 * 2. 遞增 * @return 默認(rèn)值 */ long value() default RetryWaitConst.VALUE_MILLS; /** * 最小值 * @return 最小值 */ long min() default RetryWaitConst.MIN_MILLS; /** * 最大值 * @return 最大值 */ long max() default RetryWaitConst.MAX_MILLS; /** * 影響因數(shù) * 1. 遞增重試,默認(rèn)為 {@link RetryWaitConst#INCREASE_MILLS_FACTOR} * 2. 指數(shù)模式。默認(rèn)為 {@link RetryWaitConst#MULTIPLY_FACTOR} * @return 影響因數(shù) */ double factor() default Double.MIN_VALUE; /** * 指定重試的等待時(shí)間 class 信息 * @return 重試等待時(shí)間 class */ Class extends com.github.houbb.sisyphus.api.support.wait.RetryWait> retryWait() default NoRetryWait.class; }注解的使用
定義好了注解,肯定要有注解的相關(guān)使用。
關(guān)于注解的使用,主要有兩種方式。
Proxy+CGLIB基于代理模式和字節(jié)碼增強(qiáng)。
如果是項(xiàng)目中沒(méi)有使用 spring,直接使用這種方式比較方便。
Spring-AOP可以和 spring 直接整合。
使用方式和 spring-retry 是一樣的。
sisyphus 代理模板 目的為了便于用戶更加方便地使用注解,同時(shí)又不依賴 spring。
提供基于代碼模式+字節(jié)碼增強(qiáng)實(shí)現(xiàn)的方式。
使用案例 maven 引入引入注解相關(guān)模塊。
定義測(cè)試方法${project.groupId} sisyphus-annotation ${project.version}
以下測(cè)試代碼可以參考 [spring-test]() 模塊。
MenuServiceImpl.java
public class MenuServiceImpl { public void queryMenu(long id) { System.out.println("查詢菜單..."); throw new RuntimeException(); } @Retry public void queryMenuRetry(long id) { System.out.println("查詢菜單..."); throw new RuntimeException(); } }測(cè)試
使用 RetryTemplate 進(jìn)行測(cè)試
無(wú)重試注解的方法@Test(expected = RuntimeException.class) public void templateTest() { MenuServiceImpl menuService = RetryTemplate.getProxyObject(new MenuServiceImpl()); menuService.queryMenu(1); }
日志信息
查詢菜單...
只請(qǐng)求了一次。
有注解的方法@Test(expected = RuntimeException.class) public void templateRetryTest() { MenuServiceImpl menuService = RetryTemplate.getProxyObject(new MenuServiceImpl()); menuService.queryMenuRetry(1); }
日志信息
查詢菜單... 查詢菜單... 查詢菜單...其他
當(dāng)然還有更多的配置,可以自行嘗試。
如果你想結(jié)合 spring 使用注解,請(qǐng)繼續(xù)往下看。
sisyphus spring 整合 目的類(lèi)似于 spring-retry 框架,如果你使用 spring 框架,那么整合本項(xiàng)目將會(huì)非常簡(jiǎn)單。
注解的方式和過(guò)程式編程,二者盡可能的保持一致性,你想從一種方式變?yōu)榱硪环N也比較簡(jiǎn)單。
想從 spring-retry 切換到本框架也很方便。
使用示例 maven 引入${project.groupId} sisyphus-spring ${project.version}
會(huì)默認(rèn)引入 spring 以及 AOP 相關(guān) jar。
業(yè)務(wù)代碼你可以參考 sisyphus-test 模塊。
下面模擬非常常見(jiàn)的一些業(yè)務(wù)方法。
使用 @Retry 標(biāo)識(shí)方法需要進(jìn)行重試。
SpringService.java
public interface SpringService { /** * 查詢示例代碼 * @return 結(jié)果 */ String query(); }
SpringServiceImpl.java
import com.github.houbb.sisyphus.annotation.annotation.Retry; import com.github.houbb.sisyphus.test.service.SpringService; import org.springframework.stereotype.Service; /** * @author binbin.hou * @since 0.0.4 */ @Service public class SpringServiceImpl implements SpringService { @Override @Retry public String query() { System.out.println("spring service query..."); throw new RuntimeException(); } }開(kāi)啟重試
基于注解直接如下配置即可。
使用 @EnableRetry 標(biāo)識(shí)需要開(kāi)啟重試。
@Configurable @ComponentScan(basePackages = "com.github.houbb.sisyphus.test.service") @EnableRetry public class SpringConfig { }測(cè)試代碼
import com.github.houbb.sisyphus.test.config.SpringConfig; import com.github.houbb.sisyphus.test.service.SpringService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author binbin.hou * @since 0.0.4 */ @ContextConfiguration(classes = SpringConfig.class) @RunWith(SpringJUnit4ClassRunner.class) public class SpringServiceTest { @Autowired private SpringService springService; @Test(expected = RuntimeException.class) public void queryTest() { springService.query(); } }
日志信息
spring service query... spring service query... spring service query...新特性預(yù)定 入?yún)?/b>
重試上下文添加入?yún)⑿畔?/p> 配置優(yōu)化
提供更加優(yōu)異的配置體驗(yàn)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77855.html
摘要:支持重試版本思考小明我手頭還有其他任務(wù),這個(gè)也挺簡(jiǎn)單的。與其他類(lèi)似的字節(jié)碼編輯器不同,提供了兩個(gè)級(jí)別的源級(jí)和字節(jié)碼級(jí)。另一方面,字節(jié)碼級(jí)允許用戶直接編輯類(lèi)文件作為其他編輯器。提供與其他字節(jié)碼框架類(lèi)似的功能,但主要關(guān)注性能。 系列說(shuō)明 java retry 的一步步實(shí)現(xiàn)機(jī)制。 java-retry 源碼地址 情景導(dǎo)入 簡(jiǎn)單的需求 產(chǎn)品經(jīng)理:實(shí)現(xiàn)一個(gè)按條件,查詢用戶信息的服務(wù)。 小明:好的...
摘要:包含一些狀態(tài)來(lái)決定是重試還是中止,但是這個(gè)狀態(tài)位于堆棧上,不需要將它存儲(chǔ)在全局的任何位置,因此我們將此稱(chēng)為無(wú)狀態(tài)重試。將拋出原始異常,除非在有狀態(tài)的情況下,當(dāng)沒(méi)有可用的恢復(fù),在這種情況下,它將拋出。 spring-retry 該項(xiàng)目為Spring應(yīng)用程序提供聲明式重試支持,它用于Spring Batch、Spring Integration、Apache Hadoop的Spring(以...
摘要:內(nèi)部使用了的動(dòng)態(tài)代理為目標(biāo)接口生成了一個(gè)動(dòng)態(tài)代理類(lèi),這里會(huì)生成一個(gè)動(dòng)態(tài)代理原理統(tǒng)一的方法攔截器,同時(shí)為接口的每個(gè)方法生成一個(gè)攔截器,并解析方法上的元數(shù)據(jù),生成一個(gè)請(qǐng)求模板。的核心源碼解析到此結(jié)束了,不知道是否對(duì)您有無(wú)幫助,可留言跟我交流。 Feign是一個(gè)聲明式的Web服務(wù)客戶端。這使得Web服務(wù)客戶端的寫(xiě)入更加方便 要使用Feign創(chuàng)建一個(gè)界面并對(duì)其進(jìn)行注釋。它具有可插拔注釋支持,包...
摘要:請(qǐng)求重試攔截器錯(cuò)誤解碼器在發(fā)生請(qǐng)求錯(cuò)誤包括發(fā)生異?;蛘唔憫?yīng)數(shù)據(jù)不符合預(yù)期的時(shí)候,錯(cuò)誤解碼器可將相關(guān)信息解碼到自定義異常中。 在SpringBoot項(xiàng)目直接使用okhttp、httpClient或者RestTemplate發(fā)起HTTP請(qǐng)求,既繁瑣又不方便統(tǒng)一管理。因此,在這里推薦一個(gè)適...
閱讀 3123·2021-11-18 10:02
閱讀 2628·2021-10-13 09:47
閱讀 3077·2021-09-22 15:07
閱讀 810·2019-08-30 15:43
閱讀 1824·2019-08-30 10:59
閱讀 1706·2019-08-29 15:34
閱讀 1717·2019-08-29 15:06
閱讀 454·2019-08-29 13:28