优雅!Spring的重试小工具
一、介绍
在日常项目的开发中,避免不了调用第三方服务的情况。
如果是第三方有提供SDK
包那还好说,就怕没有,第三方接口还不稳定的情况最恼火了。
这个时候,我们一般都会加上重试机制,手动捕获异常发起重试,不优雅
试试这个spring
中的工具spring-retry
如何
官网
github地址
二、使用
导入maven
依赖,使用的是SpringBoot
框架,版本号已经有管理了,直接引入即可。
记得把AOP
也引用一下
1 2 3 4 5 6 7 8
| <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
|
在SpringBoot
的启动类上加上@EnableRetry
注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.banmoon.test;
import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.retry.annotation.EnableRetry; import org.springframework.scheduling.annotation.EnableScheduling;
@EnableRetry @EnableScheduling @MapperScan("com.banmoon.test.mapper") @SpringBootApplication public class TestApplication {
public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); }
}
|
编写RetryController.java
,里面包含了模拟的server
方法,一会我们通过client
方法去调用它
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 38 39 40 41 42 43 44 45 46 47 48 49 50
| package com.banmoon.test.controller;
import com.banmoon.test.obj.dto.ResultData; import com.banmoon.test.service.RetryService; import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException;
@Slf4j @Validated @Api(tags = "重试测试") @RestController @RequestMapping("retry") public class RetryController {
@Autowired private RetryService retryService;
@GetMapping("server") public ResultData<String> server(@RequestParam Integer delay) throws TimeoutException { try { boolean timeout = delay > 5000; if (timeout) { delay = 5000; } TimeUnit.MILLISECONDS.sleep(delay); if (timeout) { throw new TimeoutException(); } } catch (InterruptedException e) { log.error("睡眠异常"); } return ResultData.success(delay+""); }
@GetMapping("client") public ResultData client(@RequestParam Integer delay) { String result = retryService.callServer(delay); return ResultData.success(result); }
}
|
client
方法用到了RetryService.java
1 2 3 4 5 6
| package com.banmoon.test.service;
public interface RetryService {
String callServer(Integer delay); }
|
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
| package com.banmoon.test.service.impl;
import cn.hutool.http.HttpUtil; import cn.hutool.socket.SocketRuntimeException; import com.alibaba.fastjson2.JSON; import com.banmoon.test.obj.dto.ResultData; import com.banmoon.test.service.RetryService; import lombok.extern.slf4j.Slf4j; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service;
import java.net.SocketTimeoutException; import java.util.HashMap; import java.util.Map;
@Slf4j @Service public class RetryServiceImpl implements RetryService {
@Override @Retryable(value = {SocketRuntimeException.class, SocketTimeoutException.class}, maxAttempts = 3) public String callServer(Integer delay) { log.info("客户端请求服务端,delay:{}", delay); Map<String, Object> params = new HashMap<>(); params.put("delay", delay); String result = HttpUtil.get("http://localhost:8089/retry/server", params, 5000); ResultData<String> data = JSON.parseObject(result, ResultData.class); return data.getData(); } }
|
主要就是这行注解
@Retryable(value = {SocketRuntimeException.class, SocketTimeoutException.class}, maxAttempts = 3)
发起重试的异常,重试的次数
具体可以看文档,或者源码
三、测试
启动服务,发送请求
响应是这样的,我们继续看控制台,成功发起重试
四、最后
在文档的示例中,我们也可以这样发起重试,如下
1 2 3 4 5 6 7 8 9
| RetryTemplate template = RetryTemplate.builder() .maxAttempts(3) .fixedBackoff(1000) .retryOn(RemoteAccessException.class) .build();
template.execute(ctx -> { });
|
我是半月,你我一同共勉!