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