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,不再重试!

    总结:

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

    郭慕荣博客园
  • 相关阅读:
    C#基础:单例模式与多线程
    C#基础:线程同步
    C#基础:C#中的数据结构
    C#基础:GC中什么是代,一共分几代
    C#基础:Dispose方法和Finalize方法在何时被调用
    C#基础:.NET中GC的运行机制
    C#基础:简述.NET中堆栈和堆的特点和差异
    PLSQL_基础系列05_视图控制WITH CHECK OPTION(案例)
    PLSQL_基础系列04_时间间隔INTERVAL(案例)
    PLSQL_基础系列03_合并操作UNION / UNION ALL / MINUS / INTERSET(案例)
  • 原文地址:https://www.cnblogs.com/jelly12345/p/15293073.html
Copyright © 2011-2022 走看看