前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >优雅!Spring的重试小工具

优雅!Spring的重试小工具

作者头像
半月无霜
发布2023-03-07 20:05:53
6010
发布2023-03-07 20:05:53
举报
文章被收录于专栏:半月无霜半月无霜

优雅!Spring的重试小工具

一、介绍

在日常项目的开发中,避免不了调用第三方服务的情况。

如果是第三方有提供SDK包那还好说,就怕没有,第三方接口还不稳定的情况最恼火了。

这个时候,我们一般都会加上重试机制,手动捕获异常发起重试,不优雅

试试这个spring中的工具spring-retry如何

image-20230306171419108
image-20230306171419108

官网

github地址

二、使用

导入maven依赖,使用的是SpringBoot框架,版本号已经有管理了,直接引入即可。

记得把AOP也引用一下

代码语言:javascript
复制
<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注解

代码语言:javascript
复制
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方法去调用它

代码语言:javascript
复制
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

代码语言:javascript
复制
package com.banmoon.test.service;

public interface RetryService {

    String callServer(Integer delay);
}
代码语言:javascript
复制
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)

发起重试的异常,重试的次数

具体可以看文档,或者源码

三、测试

启动服务,发送请求

image-20230306174646082
image-20230306174646082

响应是这样的,我们继续看控制台,成功发起重试

image-20230306170024983
image-20230306170024983

四、最后

在文档的示例中,我们也可以这样发起重试,如下

代码语言:javascript
复制
RetryTemplate template = RetryTemplate.builder()
				.maxAttempts(3)
				.fixedBackoff(1000)
				.retryOn(RemoteAccessException.class)
				.build();

template.execute(ctx -> {
    // ... do something
});

我是半月,你我一同共勉!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 优雅!Spring的重试小工具
    • 一、介绍
      • 二、使用
        • 三、测试
          • 四、最后
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档