spring-boot重试机制:Guava-Retrying

在我们正常的业务开发中,不免会发生请求第三方接口的应用场景,但由于网络不稳定的原因经常会发生一些问题,比如:请求虽然发出去,但返回的确实服务器繁忙、或者干脆没有返回信息等等,这时可以应用重试机制来解决这个问题,常用的重试有java Retry、springboot Retry与guava-retrying。这次主要介绍一下guava-retrying。guava-retrying是基于谷歌的核心类库guava的重试机制实现,本文一个常用的post与get的方法来介绍guava retrying重试机制的使用。

首先我们写一个http请求的工具类,其中有post与get方法

java 复制代码
public abstract class HttpUtil {
    public HttpUtil() {
    }


    protected JSONObject get(String requestUrl) throws IOException {
        StringBuilder buffer = new StringBuilder();a
        URL url = new URL(requestUrl);
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
        httpsURLConnection.setRequestProperty("accept", "*/*");
        httpsURLConnection.setRequestProperty("connection", "Keep-Alive");
        httpsURLConnection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        httpsURLConnection.setRequestMethod("GET");
        httpsURLConnection.connect();

        InputStream inputStream = httpsURLConnection.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

        String str;
        while ((str = bufferedReader.readLine()) != null) {
            buffer.append(str);
        }
        bufferedReader.close();
        inputStreamReader.close();
        inputStream.close();
        httpsURLConnection.disconnect();
        return JSONObject.fromObject(buffer.toString());
    }

    protected JSONObject post(String requestUrl, String outputStr) throws Exception {
        StringBuilder buffer = new StringBuilder();
        TrustManager[] tm = new TrustManager[]{new MyX509TrustManager()};
        SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
        sslContext.init(null, tm, new SecureRandom());
        SSLSocketFactory ssf = sslContext.getSocketFactory();
        URL url = new URL(requestUrl);
        HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
        httpUrlConn.setSSLSocketFactory(ssf);
        httpUrlConn.setRequestProperty("Content-type", "application/json");
        httpUrlConn.setDoOutput(true);
        httpUrlConn.setDoInput(true);
        httpUrlConn.setUseCaches(false);
        httpUrlConn.setReadTimeout(10000);
        httpUrlConn.setConnectTimeout(10000);
        httpUrlConn.setRequestMethod("POST");
        if (null != outputStr) {
            OutputStream outputStream = httpUrlConn.getOutputStream();
            outputStream.write(outputStr.getBytes(Charset.forName("UTF-8")));
            outputStream.close();
        }

        InputStream inputStream = httpUrlConn.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

        String str;
        while ((str = bufferedReader.readLine()) != null) {
            buffer.append(str);
        }

        bufferedReader.close();
        inputStreamReader.close();
        inputStream.close();
        httpUrlConn.disconnect();
        return JSONObject.fromObject(buffer.toString());
    }

    private static class MyX509TrustManager implements X509TrustManager {
        private MyX509TrustManager() {
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
}

接下来我们需要写一个类来继承HttpUtil工具类并重写其中的post方法与get方法

java 复制代码
public class HttpService extends HttpUtil {
    @Override
    protected JSONObject post(String requestUrl, String outputStr) throws Exception {
        return super.post(requestUrl, outputStr);
    }

    @Override
    protected JSONObject get(String requestUrl) throws Exception{
        return super.get(requestUrl);
    }
}

增加重试机制的策略

java 复制代码
    private final Retryer<JSONObject> retryer = RetryerBuilder.<JSONObject>newBuilder()
            .retryIfExceptionOfType(Exception.class) //根据异常重试
            .retryIfException() //发生异常重试
            .retryIfResult(Predicates.isNull()) //返回接口为null需要重试
            .withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS)) //3毫秒后重试
            .withStopStrategy(StopStrategies.stopAfterAttempt(3)) //重试次数
            .withRetryListener(new MyRetryListener()) //注册监听 监听这里我们最后说
            .build();

接下来将重试的机制配置到方法里,由于post与get的方法基本一致所以这里只列举post

java 复制代码
    @Override
    public JSONObject get(String requestUrl) {
        Callable<JSONObject> callable = () -> {
            // TODO: 业务逻辑的实现
            return super.get(requestUrl);
        };
        try {
            return retryer.call(callable);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
java 复制代码
/**
 * @Author fallrain
 * @Date 2021/3/10 15:12
 * @description:重试失败监听器,监听可以使我们做好错误日志的整理,以便后期系统的优化
 * @Version 1.0
 */
@Log4j2
public class MyRetryListener implements RetryListener {
    @Override
    public <V> void onRetry(Attempt<V> attempt) {
        if (attempt.getAttemptNumber() == 1) return;
        log.error("第{}次重试", attempt.getAttemptNumber());
        log.error("重试原因:{}", attempt.getExceptionCause().toString());
        if(attempt.getAttemptNumber()==3){
            // TODO: 若第三次重试还是存在错误,则记录错误信息
        }
    }
}
java 复制代码
//在使用时我们可以直接new一个出来使用
private HttpUtil httpUtil=new HttpService();
//也可以通过springboot IOC容器注入一个使用
@Autowired
public ServiceImpl(HttpUtil httpUtil) {
    this.httpUtil = httpUtil;
}
java 复制代码
//完整代码
@Service
public class HttpService extends HttpUtil {

    public HttpService() {
    }
    private final Retryer<JSONObject> retryer = RetryerBuilder.<JSONObject>newBuilder()
            .retryIfExceptionOfType(Exception.class) //根据异常重试
            .retryIfException()
            .retryIfResult(Predicates.isNull()) //返回接口为null需要重试
            .withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS)) //3毫秒后重试
            .withStopStrategy(StopStrategies.stopAfterAttempt(3)) //重试次数
            .withRetryListener(new MyRetryListener()) //注册重试监听
            .build();

    @Override
    public JSONObject post(String requestUrl, String outputStr) {
        Callable<JSONObject> callable = () -> super.post(requestUrl, outputStr);
        try {
            return retryer.call(callable);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public JSONObject get(String requestUrl) {
        Callable<JSONObject> callable = () -> super.get(requestUrl);
        try {
            return retryer.call(callable);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
相关推荐
悟空码字1 天前
Spring Boot 整合 MongoDB 最佳实践:CRUD、分页、事务、索引全覆盖
java·spring boot·后端
皮皮林5513 天前
拒绝写重复代码,试试这套开源的 SpringBoot 组件,效率翻倍~
java·spring boot
用户908324602735 天前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
用户8307196840826 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解6 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解6 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记6 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者7 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840827 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解7 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端