秋雨 De Blog

一个技术小白的个人博客

spring-boot重试机制:Guava-Retrying

在我们正常的业务开发中,不免会发生请求第三方接口的应用场景,但由于网络不稳定的原因经常会发生一些问题,比如:请求虽然发出去,但返回的确实服务器繁忙、或者干脆没有返回信息等等,这时可以应用重试机制来解决这个问题,常用的重试有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();
        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;
        }
    }
}
点赞

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注