依赖
<dependency>
<groupId>org.springframework.retrygroupId>
<artifactId>spring-retryartifactId>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.46version>
dependency>
代码实现
异常类
package com.retry.demo.springretry.exception;
import lombok.Builder;
import lombok.Getter;
@Builder
@Getter
public class RetryException extends RuntimeException {
private String code;
private String message;
}
主类
package net.fanci.stars;
import net.fanci.stars.listener.PropertiesListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@SpringBootApplication
@EnableRetry
public class StarsParentApplication {
public static void main(String[] args) {
// SpringApplication.run(StarsParentApplication.class, args);
SpringApplication application = new SpringApplication(StarsParentApplication.class);
//加载配置文件
application.addListeners(new PropertiesListener("config.properties"));
application.run(args);
}
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
重试类
package com.retry.demo.springretry.serivce;
import com.retry.demo.springretry.exception.RetryException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class RetryServiceImpl implements RetryService {
int i = 1;
// 需要指定 maxDelay
@Override
@Retryable(include = {RetryException.class}, maxAttempts = 4, backoff = @Backoff(delay = 3000l,maxDelay = 60 * 1000L, multiplier = 1))
public String retry() {
log.info("测试retry");
//生产环境此处应该为调用第三方接口,判断接口返回code
if (i == 3) {
return i++ + "";
}
i++;
log.info("============" + i);
RetryException retryException = RetryException.builder().code("9999").message("连接超时").build();
throw retryException;
}
@Recover
public String recover(RetryException e) {
log.info(e.getMessage());
return "6";
}
}
依赖
<dependency>
<groupId>com.github.rholdergroupId>
<artifactId>guava-retryingartifactId>
<version>2.0.0version>
dependency>
实现类
package com.retry.demo.guavaretrying;
import com.github.rholder.retry.*;
import com.google.common.base.Predicates;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
/**
* @author xxx
* @create 2018/08/12 13:29
* @description
*/
@Slf4j
public class demos {
public static void main(String[] args) {
/**
* 根据结果判断是否重试:
* 通过 counter 控制返回结果,返回结果不是 success 就进行重试,知道 counter = 5 的时候返回 success
*/
// test1();
/**
* 根据异常判断是否重试:
* 如果 counter < 5 则抛出异常,等于 5 则正常返回,停止重试
*/
// test2();
/**
* 重试策略——设定无限重试:
* 在有异常情况下,无限重试,直到返回正常有效结果
*/
// test3();
/**
* 重试策略——设定最大的重试次数:
* 在有异常情况下,最多重试3次,如果超过3次则会抛出异常
*/
// test4();
/**
* 等待策略——设定重试等待固定时长策略:
* 设定每次重试等待间隔固定为100ms
*/
// test5();
/**
* 等待策略——设定重试等待时长固定增长策略:
* 设定初始等待时长值,并设定固定增长步长,但不设定最大等待时长
* 等待时长依次为200ms、300ms、400ms、500ms
*/
// test6();
/**
* 等待策略——设定重试等待时长按斐波那契数列增长策略:
* 根据multiplier值按照指数级增长等待时长,并设定最大等待时长
* 等待时长依次为200ms、400ms、800ms、1000ms
*/
// test7();
/**
* 等待策略——设定重试等待时长按指数增长策略:
* 根据multiplier值按照斐波那契数列增长等待时长,并设定最大等待时长,斐波那契数列:1、1、2、3、5、8、13、21、34、……
* 等待时长依次为100ms、100ms、200ms、300ms
*/
// test8();
/**
* 等待策略——组合重试等待时长策略:
* 组合ExponentialWaitStrategy和FixedWaitStrategy策略
* 等待时长依次为100(50+50)ms、150(100+50)ms、250(200+50)ms、450(400+50)ms
*/
// test9();
/**
* 定义两个监听器,分别打印重试过程中的细节,未来可更多的用于异步日志记录,亦或是特殊处理:
* RetryListener会根据注册顺序执行
*/
test10();
}
private static void test10() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
// 监听器 1
RetryListener retryListener1 = new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
// 第几次重试,(注意:第一次重试其实是第一次调用)
log.info("[retry]time=" + attempt.getAttemptNumber());
// 距离第一次重试的延迟
log.info(",delay=" + attempt.getDelaySinceFirstAttempt());
// 重试结果: 是异常终止, 还是正常返回
log.info(",hasException=" + attempt.hasException());
log.info(",hasResult=" + attempt.hasResult());
// 是什么原因导致异常
if (attempt.hasException()) {
log.info(",causeBy=" + attempt.getExceptionCause().toString());
} else {
// 正常返回时的结果
log.info(",result=" + attempt.getResult());
}
// 增加了额外的异常处理代码
try {
V result = attempt.get();
log.info(",rude get=" + result);
} catch (ExecutionException e) {
log.error("this attempt produce exception." + e.getCause().toString());
}
}
};
// 监听器 2
RetryListener retryListener2 = new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
log.info("myRetryListener2 : [retry]time=" + attempt.getAttemptNumber());
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.neverStop())
.withRetryListener(retryListener1)
.withRetryListener(retryListener2)
.build();
try {
String result = retryer.call(callable);
log.info("result:{}", result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test9() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.neverStop())
.withWaitStrategy(WaitStrategies.join(WaitStrategies.exponentialWait(25, 500, TimeUnit.MILLISECONDS)
, WaitStrategies.fixedWait(50, TimeUnit.MILLISECONDS)))
.build();
try {
String result = retryer.call(callable);
log.info("result:{}", result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test8() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.neverStop())
.withWaitStrategy(WaitStrategies.fibonacciWait(100, 1000, TimeUnit.MILLISECONDS))
.build();
try {
String result = retryer.call(callable);
log.info("result:{}", result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test7() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.neverStop())
.withWaitStrategy(WaitStrategies.exponentialWait(100, 1000, TimeUnit.MILLISECONDS))
.build();
try {
String result = retryer.call(callable);
log.info("result:{}", result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test6() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.neverStop())
.withWaitStrategy(WaitStrategies.incrementingWait(200, TimeUnit.MILLISECONDS, 100, TimeUnit.MILLISECONDS))
.build();
try {
String result = retryer.call(callable);
log.info("result:{}", result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test5() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.neverStop())
.withWaitStrategy(WaitStrategies.fixedWait(100, TimeUnit.MILLISECONDS))
.build();
try {
String result = retryer.call(callable);
log.info("result:{}", result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test4() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.withWaitStrategy(WaitStrategies.fixedWait(100, TimeUnit.MILLISECONDS))
.build();
try {
String result = retryer.call(callable);
log.info("result:{}", result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test3() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.neverStop())
.build();
try {
String result = retryer.call(callable);
log.info("result:{}", result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test2() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
throw new RuntimeException("error");
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.neverStop())
.build();
try {
retryer.call(callable);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
private static void test1() {
Callable<String> callable = new Callable<String>() {
int counter = 0;
@Override
public String call() throws Exception {
counter++;
log.info("counter--------{}", counter);
if (counter < 5) {
return "error";
} else {
return "success";
}
}
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfResult(result -> !result.contains("success"))
.withStopStrategy(StopStrategies.neverStop())
.build();
try {
retryer.call(callable);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
}
在需要异步执行的方法上使用@async
注解,其实就是线程
在主类添加注解
@SpringBootApplication
@EnableAsync
public class StarsParentApplication {
public static void main(String[] args) {
}
}