在调用第三方接口或者使用mq时,会出现网络抖动,连接超时等网络异常,所以需要重试。
1、引入jar包
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency>
2、模拟网络异常,创建一个异常
package com.demo.exception; import lombok.Builder; import lombok.Getter; /** * Created by huguoju on 2017/4/13. */ @Builder @Getter public class RetryException extends RuntimeException { private String code; private String message; }
3、在Application上添加@EnableRetry开启Retry服务
@EnableRetry public class SpringbootApplication {
4、在service模拟访问异常,抛出异常
package com.demo.service.impl; import com.demo.exception.RetryException; import com.demo.service.RetryService; 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; /** * Created by huguoju on 2017/4/13. */ @Service("retryService") @Slf4j public class RetryServiceImpl implements RetryService { int i=1; @Override @Retryable(value = {RuntimeException.class},maxAttempts = 4,backoff = @Backoff(delay = 1000l,multiplier = 1)) public String retry() { log.info("测试retry"); i++;//生产环境此处应该为调用第三方接口,判断接口返回code if(i==3){ return i+""; } RetryException retryException=RetryException.builder().code("9999").message("连接超时").build(); throw retryException; } @Recover public String recover(RetryException e){ log.info(e.getMessage()); return "6"; } }
说明:
@Retryable:标注此注解的方法在发生异常时会进行重试参数说明:value:抛出指定异常才会重试include:和value一样,默认为空,当exclude也为空时,默认所以异常exclude:指定不处理的异常maxAttempts:最大重试次数,默认3次backoff:重试等待策略,默认使用@Backoff,@Backoff的value默认为1000L,multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为2,则第一次重试为1秒,第二次为2秒,第三次为4秒@Recover:用于@Retryable重试失败后处理方法,此方法里的异常一定要是@Retryable方法里抛出的异常,否则不会调用这个方法5、在其他service里调用上面的service抛出异常
@Override public Map testRetry() { Map map= Maps.newHashMap(); String s=retryService.retry(); if (s.equals("3")){ log.info("成功啦啦啦啦啦啦啦啦"); }else { log.info("失败了"); } map.put("result",s); return map; }
6、定义测试controller
package com.demo.controller; import com.demo.service.RetryService; import com.demo.service.TestService; import com.google.common.collect.Maps; import io.swagger.annotations.Api; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.Map; /** * Created by huguoju on 2017/4/13. */ @RestController @RequestMapping("retry") @Api(value = "重试机制",tags = "重试机制") public class RetryController { @Autowired public TestService testService; @RequestMapping(value = "testRetry",method = {RequestMethod.POST,RequestMethod.GET},produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Map testRetry(){ Map map=Maps.newHashMap(); try { map= testService.testRetry(); return map; }catch (Exception e){ e.printStackTrace(); return map; } } }
访问controller,看日志输出
15:21:30 WARN [qtp1129243682-21] com.atomikos.icatch.imp.TransactionServiceImp - Attempt to create a transaction with a timeout that exceeds com.atomikos.icatch.max_timeout - truncating to: 300000 15:21:30 INFO [qtp1129243682-21] com.atomikos.icatch.imp.BaseTransactionManager - createCompositeTransaction ( 10000000 ): created new ROOT transaction with id 10.3.5.31.tm0000100002 15:21:30 INFO [qtp1129243682-21] com.demo.service.impl.RetryServiceImpl - 测试retry 15:21:31 INFO [qtp1129243682-21] com.demo.service.impl.RetryServiceImpl - 测试retry 15:21:31 INFO [qtp1129243682-21] com.demo.service.impl.TestServiceImpl - 成功啦啦啦啦啦啦啦啦 15:21:31 INFO [qtp1129243682-21] com.atomikos.icatch.imp.CompositeTransactionImp - commit() done (by application) of transaction 10.3.5.31.tm0000100002
要测试@Recover,即一直异常,只需要把RetryServiceImpl里的if(i==3)改为if(i==6),把调用service里if(s.equals("3"))改完if(s.equals("6)),然后重新访问,日志:
15:26:54 WARN [qtp1870436181-20] com.atomikos.icatch.imp.TransactionServiceImp - Attempt to create a transaction with a timeout that exceeds com.atomikos.icatch.max_timeout - truncating to: 300000 15:26:54 INFO [qtp1870436181-20] com.atomikos.icatch.imp.BaseTransactionManager - createCompositeTransaction ( 10000000 ): created new ROOT transaction with id 10.3.5.31.tm0000100003 15:26:54 INFO [qtp1870436181-20] com.demo.service.impl.RetryServiceImpl - 测试retry 15:26:55 INFO [qtp1870436181-20] com.demo.service.impl.RetryServiceImpl - 测试retry 15:26:56 INFO [qtp1870436181-20] com.demo.service.impl.RetryServiceImpl - 测试retry 15:26:57 INFO [qtp1870436181-20] com.demo.service.impl.RetryServiceImpl - 测试retry 15:26:57 INFO [qtp1870436181-20] com.demo.service.impl.RetryServiceImpl - 连接超时 15:26:57 INFO [qtp1870436181-20] com.demo.service.impl.TestServiceImpl - 成功啦啦啦啦啦啦啦啦 15:26:57 INFO [qtp1870436181-20] com.atomikos.icatch.imp.CompositeTransactionImp - commit() done (by application) of transaction 10.3.5.31.tm0000100003