zoukankan      html  css  js  c++  java
  • Spring Retry原理总结(二)

    Spring Retry原理总结的原理其实就是拦截器+代理+反射来进行实现的。代码展示如下所示:

    注解定义

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Retryable {
    
        int maxAttemps() default 0;
    
    }

    代理实现
    以Cglib作为代理工具,先来写个Callback实现,这也是重试的实现的核心逻辑。注意(invokeSuper和invoke的区别)

    public class AnnotationAwareRetryOperationsInterceptor implements MethodInterceptor {
    
        /**
         * 记录重试次数
         */
        private int times = 0;
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            //获取拦截的方法中的Retryable注解
            Retryable retryable = method.getAnnotation(Retryable.class);
            if(retryable == null){
                return proxy.invokeSuper(obj,args);
            }else{
                //有Retryable注解,加入异常重试逻辑
                int maxAttemps = retryable.maxAttemps();
                try {
                    return proxy.invokeSuper(obj,args);
                } catch (Throwable e) {
                    if(times++ == maxAttemps){
                        System.out.println("已达最大重试次数:" + maxAttemps + ",不再重试!");
                    }else{
                        System.out.println("调用" + method.getName() + "方法异常,开始第" + times +"次重试。。。");
                        //注意这里不是invokeSuper方法,invokeSuper会退出当前interceptor的处理
                        proxy.invoke(obj,args);
                    }
                }
            }
            return null;
        }
    
    }

    然后是写个代理类,使用AnnotationAwareRetryOperationsInterceptor作为拦截器。

    public class SpringRetryProxy {
    
        public Object newProxyInstance(Object target){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(target.getClass());
            enhancer.setCallback(new AnnotationAwareRetryOperationsInterceptor());
            return enhancer.create();
        }
    
    }

    测试
    通过一个用户相关的业务方法来测试上面的代码
    接口定义:

    public interface UserFacade {
    
        void add() throws Exception;
    
        void query() throws Exception;
    }

    接口实现:

    public class UserFacadeImpl implements UserFacade {
    
        @Override
        public void add() throws Exception {
            System.out.println("添加用户。。。");
            throw new RuntimeException();
        }
    
        @Override
        @Retryable(maxAttemps = 3)
        public void query() {
            System.out.println("查询用户。。。");
            throw new RuntimeException();
        }
    
    }

    测试:

        public static void main(String[] args) throws Exception{
    
            UserFacadeImpl user = new UserFacadeImpl();
            //SpringRetry代理测试
            SpringRetryProxy springRetryProxy = new SpringRetryProxy();
            UserFacade u = (UserFacade)springRetryProxy.newProxyInstance(user);
            //u.add();//失败不重试
            u.query();//失败重试
        }

    运行效果如下:

    查询用户。。。
    调用query方法异常,开始第1次重试。。。
    查询用户。。。
    调用query方法异常,开始第2次重试。。。
    查询用户。。。
    调用query方法异常,开始第3次重试。。。
    查询用户。。。
    已达最大重试次数:3,不再重试!

    总结:

    其实重试的原理就是拦截+代理+反射。

    郭慕荣博客园
  • 相关阅读:
    Python 函数 切片 迭代 列表生成器
    Python中各种集合 list tuple set dict
    Python学习 常识+基础基础
    《零基础学习Python》01
    原生API实现拖拽上传文件实践
    美团点评面试题小结(测试开发和前端开发)
    从实践的角度理解cookie的几个属性
    一道javascript面试题(闭包与函数柯里化)
    marked插件在线实时解析markdown的web小工具
    Github Page+Bmob实现简单动态功能
  • 原文地址:https://www.cnblogs.com/jelly12345/p/15293073.html
Copyright © 2011-2022 走看看