• springretry 使用示例(两种 命令式、声明式)


    说明:业务开发过程中经常遇到需要对接第三方接口获取第三方结果,当遇到网络问题调用失败的时候,需要去重试调用。而spring-retry就提供了这样的支持

    依赖:

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
    </dependency>

    主启动类开启注解 支持重试

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
    import org.springframework.retry.annotation.EnableRetry;
    
    @EnableRetry
    @SpringBootApplication
    public class MsgApplication extends SpringBootServletInitializer {
    
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            return builder.sources(MsgApplication.class);
        }
        
        public static void main(String[] args) {
            SpringApplication.run(MsgApplication.class, args);
        }
    
    }

    命令式

    初始化重试模板,放到spring容器中

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.retry.annotation.EnableRetry;
    import org.springframework.retry.backoff.FixedBackOffPolicy;
    import org.springframework.retry.policy.SimpleRetryPolicy;
    import org.springframework.retry.support.RetryTemplate;
    
    /**
     * 全局Bean定义
     */
    @Configuration
    @EnableRetry
    public class RetryConfig {
    
        /**
         * Spring-retry 失败重试机制调用模板
         * @return
         */
        @Bean
        public RetryTemplate retryTemplate() {
            RetryTemplate retryTemplate = new RetryTemplate();
            // 最大重试次数策略 默认3次 自定义6次
            SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(6);
            retryTemplate.setRetryPolicy(simpleRetryPolicy);
            FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
            // 重试间隔 每隔1s后再重试
            fixedBackOffPolicy.setBackOffPeriod(1000);
            retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
            return retryTemplate;
        }
    }

     具体的业务代码

    import com.alibaba.fastjson.JSONObject;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.retry.RetryCallback;
    import org.springframework.retry.RetryContext;
    import org.springframework.retry.support.RetryTemplate;
    import org.springframework.stereotype.Service;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Service
    public class RetryServiceImpl implements RetryService {
    
        private static Logger logger = LoggerFactory.getLogger(RetryServiceImpl.class);
    
        @Autowired
        private RetryTemplate retryTemplate;
    @Autowired private RestTemplate restTemplate; @Override public Map
    <String, Object> retrySendForJson(String url, String param) throws Exception { logger.info("第三方接口重试调用入参: url:{},param:{}", url, param); Map<String, Object> res = retryTemplate.execute(new RetryCallback<Map<String, Object>, Exception>() { @Override public Map<String, Object> doWithRetry(RetryContext context) throws Exception{ Map<String, Object> result = restTemplate.getForObject(url, Map.class, param); logger.info("第三方接口重试第"+context.getRetryCount()+"次调用结果:result:{}", JSONObject.toJSONString(result)); if ("0".equals((String)result.get("code")) ){ throw new Exception("调用接口失败,Http Code是"+result.get("httpCode")); } return result; } },context -> { logger.info("第三方接口重试调用兜底方法执行,重试了" + context.getRetryCount() + "次"); String message = context==null?"": context.getLastThrowable()==null?"": context.getLastThrowable().getMessage()==null?"":context.getLastThrowable().getMessage(); Map<String, Object> map = new HashMap<>(); map.put("code", "0"); map.put("httpCode", 0); map.put("msg",message); logger.info("第三方接口重试调用兜底方法执行结果: result:{}", JSONObject.toJSONString(map)); return map; }); return res; } }

    注意 :doWithRetry方法体中 必须明确的抛出了异常,才会重试。如果doWithRetry方法体中只有一行调用别的方法的代码比如methodA,若methodA中将异常捕获了,则不会重试!!!

     声明式

     声明式的只需要在对应的业务代码出使用响应的注解即可

    import com.alibaba.fastjson.JSON;
    import io.netty.channel.ConnectTimeoutException;
    import org.checkerframework.checker.units.qual.A;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpEntity;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.MediaType;
    import org.springframework.remoting.RemoteAccessException;
    import org.springframework.retry.RetryCallback;
    import org.springframework.retry.RetryContext;
    import org.springframework.retry.annotation.Backoff;
    import org.springframework.retry.annotation.EnableRetry;
    import org.springframework.retry.annotation.Recover;
    import org.springframework.retry.annotation.Retryable;
    import org.springframework.retry.policy.SimpleRetryPolicy;
    import org.springframework.retry.support.RetryTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.ResourceAccessException;
    import org.springframework.web.client.RestTemplate;
    
    import java.net.ConnectException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.atomic.AtomicInteger;
    
    @Service
    @Configuration
    @EnableRetry
    public class TestRetryService{
    
    
       @Autowired
       private RestTemplate restTemplate;
    
       private AtomicInteger counts = new AtomicInteger(1);
    
        //maxAttempts最大重试次数 delay延时多久执行 默认单位ms  multiplier 延时指数 第一次1s后,往后2s后 4s后 8s后
        @Retryable(value = {Exception.class}, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
        public String service(String url, String json) {
            System.out.println(counts.getAndIncrement());
            if (counts.get() ==1){
                url = "http://127.0.0.1:8081";
            }else if (counts.get() ==2){
                Map<String, Object> m = null;
                System.out.println(m.get("aa"));
            }else if (counts.get() ==3){
                List<String> list = new ArrayList<>();
                System.out.println(list.get(1));
            }else if (counts.get() ==4){
                int i = 1/0;
            }
            else{
                url = "http://127.0.0.1:8080";
            }
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/json; charset=UTF-8"));
            HttpEntity<String> formEntity = new HttpEntity<>(json, headers);
            String result = restTemplate.postForObject(url, formEntity, String.class);
            System.out.println(result);
            //throw new RemoteAccessException("here" + counts.get());
            return result;
        }
    
    //    @Recover
    //    public String recover(ConnectTimeoutException e) {
    //        System.out.println("连接超时重试机制"+counts.get()+"次已完成,依然连接超时..");
    //        return "连接超时重试机制"+counts.get()+"次已完成,依然连接超时..";
    //    }
    //
    //    @Recover
    //    public String recover(RemoteAccessException e) {
    //        System.out.println("远程地址不可用重试机制"+counts.get()+"次已完成,依然读取超时..");
    //        return "远程地址不可用重试机制"+counts.get()+"次已完成,依然读取超时..";
    //    }
    //
    //    @Recover
    //    public String recover(ConnectException e) {
    //        System.out.println("连接失败重试机制"+counts.get()+"次已完成,依然读取超时..a");
    //        return "连接失败重试机制"+counts.get()+"次已完成,依然读取超时..a";
    //    }
    //
    //    @Recover
    //    public String recover(NullPointerException e){
    //        System.out.println("空指针异常失败重试"+counts.get()+"次已完成");
    //        return "空指针异常失败重试"+counts.get()+"次已完成";
    //    }
    
        @Recover
        public String recover(Exception e,String url, String json){
            System.out.println("异常失败重试"+counts.get()+"次已完成");
            System.out.println("参数url:"+url+",json"+json);
            if (e.getCause() instanceof ConnectException){
                System.out.println("连接超时异常");
            }
            return "异常失败重试"+counts.get()+"次已完成";
        }
    }

    注意:这里测试了不同的异常(空指针、数组下标越界、连接超时、等),进行不同的兜底异常处理,但是有点麻烦,所以直接针对Exception进行了处理,在最后一个recover中可以针对异常进行区别处理

    官网:https://github.com/spring-projects/spring-retry

    中文版:https://my.oschina.net/itsaysay/blog/3131501

    其他相关优秀文章:

    https://developer.aliyun.com/article/92899

    https://blog.csdn.net/u010979642/article/details/114368258

  • 相关阅读:
    每日记载内容总结33
    华为机试-尼科彻斯定理
    华为机试-求最大连续bit数
    华为机试-合法IP
    华为机试-票数统计
    华为机试-等差数列
    华为机试-自守数
    中序表达式转后序表式式
    华为机考 给你一个N*M的矩阵,每个位置的值是0或1,求一个面积最大的子矩阵,这个矩阵必须是一个正方形,且里面只能由1构成,输出最大的正方形边长。其中n,m<=400;
    华为机试-求解立方根
  • 原文地址:https://www.cnblogs.com/xuchao0506/p/15552095.html
Copyright © 2020-2023  润新知