当我们调用一个接口可能由于网络等原因造成第一次失败,再去尝试就成功了,这就是重试机制,spring支持重试机制,并且在Spring Cloud中可以与Hystaix结合使用,可以避免访问到已经不正常的实例。 但是切记非幂等情况下慎用重试
加入依赖
org.springframework.retry spring-retry
在主类上加入 @EnableRetry 注解
1 2 3 4 5 6 7 8 9 | @EnableRetry //开启重试机制 @EnableAutoConfiguration //开启自动配置 @SpringBootApplication public class SpringBootApplication { public static void main(String[] args) { SpringApplication.run(SpringBootApplication.class, args); } } |
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Recover; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; import java.time.LocalTime; @Service public class RetryService { private final static Logger logger = LoggerFactory.getLogger(RetryService.class); private final int totalNum = 100000; @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 1.5)) public void retry(int num) { logger.info("减库存开始" + LocalTime.now()); try { int i = 1 / 0; } catch (Exception e) { logger.error("illegal"); } if (num <= 0) { throw new IllegalArgumentException("数量不对"); } logger.info("减库存执行结束" + LocalTime.now()); } @Recover public void recover(Exception e) { logger.warn("减库存失败!!!" + LocalTime.now()); } } |
1 2 3 4 5 6 7 8 9 10 11 | public class RetryServiceTest extends BaseTest { @Autowired private RetryService retryService; @Test public void retry() { int count = retryService.retry(-1); System.out.println("库存为 :" + count); } } |
结果:
1 2 3 4 5 6 7 8 9 | 2019-07-10 09:52:08.691 INFO 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : 减库存开始09:52:08.691 2019-07-10 09:52:08.691 ERROR 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : illegal 2019-07-10 09:52:10.695 INFO 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : 减库存开始09:52:10.695 2019-07-10 09:52:10.696 ERROR 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : illegal 2019-07-10 09:52:13.701 INFO 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : 减库存开始09:52:13.701 2019-07-10 09:52:13.709 ERROR 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : illegal 2019-07-10 09:52:18.212 INFO 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : 减库存开始09:52:18.212 2019-07-10 09:52:18.214 ERROR 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : illegal 2019-07-10 09:52:18.214 WARN 21433 --- [ XNIO-2 task-1] c.c.c.serviceImpl.TestServiceImpl : 减库存失败!!!09:52:18.214 |
注解说明
@Retryable的参数说明:
- value:抛出指定异常才会重试
- include:和value一样,默认空,当exclude也为空时,所有异常都重试
- exclude:指定不处理的异常
- maxAttempts:最大重试次数,默认3次
- backoff:重试等待策略,默认使用@Backoff
@Backoff注解
- delay:指定延迟后重试
- multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。
@Recover注解
- 当重试到达指定次数时,被注解的方法将被回调,可以在该方法中进行日志处理。需要注意的是发生的异常和入参类型一致时才会回调。
注意
-
使用了@Retryable的方法不能在本类被调用,不然重试机制不会生效。也就是要标记为@Service,然后在其它类使用@Autowired注入或者@Bean去实例才能生效。
-
要触发@Recover方法,那么在@Retryable方法上不能有返回值,只能是void才能生效。
-
非幂等情况下慎用
-
使用了@Retryable的方法里面不能使用try…catch包裹,要在方法上抛出异常,不然不会触发。