• 首页
  • 留言板
  • 关于
秋雨 De Blog
一个技术小白的个人博客
  1. 首页
  2. spring boot
  3. 正文

spring-boot重试机制:Guava-Retrying

2021年4月11日 1069点热度 1人点赞 0条评论

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

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

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方法

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);
    }
}

增加重试机制的策略

    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

    @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;
        }
    }
/**
 * @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: 若第三次重试还是存在错误,则记录错误信息
        }
    }
}
//在使用时我们可以直接new一个出来使用
private HttpUtil httpUtil=new HttpService();
//也可以通过springboot IOC容器注入一个使用
@Autowired
public ServiceImpl(HttpUtil httpUtil) {
    this.httpUtil = httpUtil;
}
//完整代码
@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;
        }
    }
}
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: 暂无
最后更新:2021年8月12日

fallrain

种一棵树最好的时间是十年前,其次是现在。

点赞
< 上一篇

文章评论

取消回复

fallrain

种一棵树最好的时间是十年前,其次是现在。

最新 热点 随机
最新 热点 随机
基于socket实现一个简易的web服务器——非阻塞的模式 wordpress自定义小工具增加友链(二) 基于socket实现一个简易的web服务器 关于进程互斥-Peterson(皮特森)算法的讨论 spring-boot重试机制:Guava-Retrying wordpress自定义小工具增加友链(一)
shiro框架多realm权限认证配置 基于socket实现一个简易的web服务器——非阻塞的模式 线程实现的三种方法及优缺点——内核实现 用户实现 混合实现 c++ lambda表达式 为wordpress博客添加留言板 基于socket实现一个简易的web服务器
最近评论
ukk 发布于 4 天前(08月07日) 可以啊我也去掉了。
我在吃大西瓜呢 发布于 9 个月前(11月16日) int turn; int turnGroup; int interested[n]; int...
我在吃大西瓜呢 发布于 9 个月前(11月12日) 你好,我想问一下 ,加入是4个进程呢?Peterson算法如何实现呢?
xirry 发布于 3 年前(04月13日) 哈喽~
最近留言
april 发布于 1 个月前(07月09日) 支持一下,博主快来更新啦
yingfeng 发布于 3 个月前(05月21日) 咕咕咕
ivkeji 发布于 1 年前(05月30日) 这就博主自己弄的留言板吗?
麦兜 发布于 1 年前(02月23日) :eek: 不明觉厉,加油加油!
友情连接
猫饭莲梦青语考拉软件问轩博客cherish烟草的香味范文泉博客迎風别葉

吉ICP备18007356号

吉公网安备22020302000184号

Theme Kratos Made By Seaton Jiang

COPYRIGHT © 2022 秋雨 De blog ALL RIGHTS RESERVED