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 小时前
分布式生成 ID 策略的演进和最佳实践,含springBoot 实现(Java版本)
java·spring boot·分布式
秋千码途1 小时前
小架构step系列07:查找日志配置文件
spring boot·后端·架构
seventeennnnn4 小时前
谢飞机的Java高级开发面试:从Spring Boot到分布式架构的蜕变之旅
spring boot·微服务架构·java面试·分布式系统·电商支付
超级小忍5 小时前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
时间会给答案scidag6 小时前
报错 400 和405解决方案
vue.js·spring boot
Wyc724096 小时前
SpringBoot
java·spring boot·spring
ladymorgana8 小时前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
GJCTYU9 小时前
spring中@Transactional注解和事务的实战理解附代码
数据库·spring boot·后端·spring·oracle·mybatis
风象南10 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
写不出来就跑路11 小时前
暑期实习感悟与经验分享:从校园到职场的成长之路
java·开发语言·经验分享·spring boot