java 重试_Java重试机制修改
最近無意間看到了一段代碼,實(shí)話實(shí)說看的我有點(diǎn)難受,剛開始的時(shí)候還略微有點(diǎn)懵,只是感覺代碼很長(zhǎng)。等我捋了一遍之后,發(fā)現(xiàn)是一段調(diào)用遠(yuǎn)程接口,失敗進(jìn)行重試功能的代碼。代碼如下:
image.png
方法用到了遞歸,在重試次數(shù)小于零跳出。
說一下存在的問題吧:
接口重試和業(yè)務(wù)本身不發(fā)生關(guān)系,所以具有很高的耦合性
方法采用遞歸實(shí)現(xiàn),有棧溢出的風(fēng)險(xiǎn)
重試邏輯無法進(jìn)行重用
可配置性比較低
看下怎么改一下:
-抽離出重試代碼,預(yù)留接口,業(yè)務(wù)代碼填入,抽離工具類如下:
public abstract class MyRetryTemplate {
//重試次數(shù)
private int retryTime;
//重試時(shí)間
private int sleepTime;
//是否倍數(shù)增長(zhǎng)
private boolean multiple = false;
/**
* 執(zhí)行業(yè)務(wù)方法邏輯,由實(shí)現(xiàn)類實(shí)現(xiàn)
*
* @return
*/
public abstract T remote() throws Exception;
public T execute() throws InterruptedException {
for (int i = 1; i < retryTime + 1; i++) {
try {
return remote();
} catch (Exception e) {
System.out.println(e.getMessage());
if (multiple){
Thread.sleep(sleepTime);
}
else{
Thread.sleep(sleepTime * (i));
}
}
}
return null;
}
public T submit(ExecutorService executorService) {
Future submit = executorService.submit((Callable) () -> execute());
try {
return (T) submit.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return null;
}
public MyRetryTemplate setRetryTime(int retryTime) {
this.retryTime = retryTime;
return this;
}
public MyRetryTemplate setSleepTime(int sleepTime) {
this.sleepTime = sleepTime;
return this;
}
public MyRetryTemplate setMultiple(boolean multiple) {
this.multiple = multiple;
return this;
}
}
上面的類中,值定義了重試的次數(shù),間隔的時(shí)間,和時(shí)間的增長(zhǎng)參數(shù),預(yù)留了remote()抽象方法,交由具體的實(shí)現(xiàn)類來實(shí)現(xiàn)。類中使用了泛型,支持返回不同的對(duì)象。并且支持同步和異步調(diào)用。
看下修改后的代碼,如下:
image.png
是不是感覺一下清爽了很多,這里重試相關(guān)的參數(shù),我直接寫死在了代碼中,可以通過配置文件和數(shù)據(jù)庫配置引入。這個(gè)方法應(yīng)該還能精簡(jiǎn),最后兩句感覺還是有點(diǎn)多余,由于不知道是干啥的, 就暫且留在這吧。
修改后的代碼,雖然解決了一些上面的問題,但是并沒有完全解決,代碼的侵入性,上面已經(jīng)說了既然這是重試的邏輯,就不應(yīng)該出現(xiàn)在代碼中。有沒有解決的辦法呢,有,切面。
下面看下通過切面該怎么實(shí)現(xiàn)。
首先定義一個(gè)注解:
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {
int count() default 0 ;
long sleep() default 0 ;
}
定義切面
@Aspect
@Component
public class RetryAspect {
ExecutorService executorService = Executors.newFixedThreadPool(3);
@Around(value = "@annotation(Retry)")
public Object execute(ProceedingJoinPoint point, Retry retry) throws InterruptedException {
System.out.println("----------------- Aspect ---------------------");
MyRetryTemplate myRetryTemplate = new MyRetryTemplate() {
@Override
public ParametersHolder remote() throws Throwable {
return (ParametersHolder) point.proceed();
}
}.setRetryTime(3).setSleepTime(10000).submit(executorService);
return submit;
}
}
最終實(shí)現(xiàn):
image.png
在注解中,添加自定義的參數(shù),便可以實(shí)現(xiàn)零侵入,也更容易實(shí)現(xiàn)方法的復(fù)用,如果有其他的業(yè)務(wù)需要實(shí)現(xiàn)重試,直接在業(yè)務(wù)方法上添加注解即可。
如果不想用這種方法,也可以借助第三方工具guava-retrying和 spring-retry 來實(shí)現(xiàn)此功能。
總結(jié)
以上是生活随笔為你收集整理的java 重试_Java重试机制修改的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java自动部署maven_Maven+
- 下一篇: java手机号判断运营商_用Java对手