Java Spring AOP-正确配置重试建议

Java Spring AOP-正确配置重试建议,java,spring,aop,spring-aop,Java,Spring,Aop,Spring Aop,我是SpringAOP新手,一直在做一些实验 我正试图通过SpringAOP为我的一个项目设置重试和速率限制。 用例如下所示:- 检查TPS是否可用。如果不是,则抛出ThrottledException 如果抛出节流异常,重试 我遇到的问题是:这个节流&重试组合正在运行一个无限循环(如果TPS=0)。也就是说,重试在“x”次尝试后不会停止 我的节流拦截器(在较高级别)如下所示: @Before("<pointcut>") public void invoke() throws Thr

我是SpringAOP新手,一直在做一些实验

我正试图通过SpringAOP为我的一个项目设置重试和速率限制。 用例如下所示:-

  • 检查TPS是否可用。如果不是,则抛出
    ThrottledException
  • 如果抛出
    节流异常
    重试
  • 我遇到的问题是:这个节流&重试组合正在运行一个无限循环(如果TPS=0)。也就是说,重试在“x”次尝试后不会停止

    我的节流拦截器(在较高级别)如下所示:

    @Before("<pointcut>")
    public void invoke() throws ThrottlingException {
            if (throttler.isThrottled(throttleKey)) {
                throw new ThrottlingException("Call Throttled");
        }
    }
    
    @AfterThrowing(pointcut="execution(* com.company.xyz.method())", throwing="exception")
    public Object invoke(JoinPoint jp, ThrottlingException exception) throws Throwable {
        return RetryingCallable.newRetryingCallable(new Callable<Object>() {
    
            @Override
            public Object call() throws Exception {
                    MethodSignature  signature = (MethodSignature) p.getSignature();
                    Method method = signature.getMethod();
                    return method.invoke(jp.getThis(), (Object[]) null);
            }
    
        }, retryPolicy).call();
    }
    
    正如我所看到的,这里的问题是,在每个
    节流异常
    上,都会应用一个新的
    重试建议
    ,而不是以前的建议生效


    有关如何解决此问题的任何信息?

    免责声明:我不是Spring用户,因此我将在这里介绍一个纯AspectJ解决方案。不过,在SpringAOP中,它应该以同样的方式工作。您需要更改的唯一一件事是将方面优先级配置从
    @declarePresence
    切换到
    @Order
    ,如中所述

    驱动程序应用程序:

    package de.scrum\u master.app;
    公共类应用程序{
    公共静态void main(字符串[]args){
    新应用程序().doSomething();
    }
    公共无效剂量测定法(){
    System.out.println(“做某事”);
    }
    }
    
    限制异常类:

    package de.scrum\u master.app;
    公共类ThrottlingException扩展了RuntimeException{
    私有静态最终长serialVersionUID=1L;
    公共节流异常(字符串arg0){
    超级(arg0);
    }
    }
    
    节流拦截器:

    为了模拟节流情况,我创建了一个helper方法
    isThrottled()
    ,它在三分之二的情况下随机返回
    true

    package de.scrum\u master.aspect;
    导入java.util.Random;
    导入org.aspectj.lang.JoinPoint;
    导入org.aspectj.lang.annotation.Aspect;
    导入org.aspectj.lang.annotation.Before;
    导入de.scrum_master.app.ThrottlingException;
    @面貌
    公共类节流interceptor{
    私有静态最终随机=新随机();
    @在(“执行(*doSomething())之前)
    公共void调用(JoinPoint thisJoinPoint)引发ThrottlingException{
    System.out.println(getClass().getSimpleName()+“->”+此连接点);
    如果(isThrottled()){
    抛出新的ThrottlingException(“调用throttling”);
    }
    }
    私有布尔值isThrottled(){
    返回RANDOM.nextInt(3)>0;
    }
    }
    
    重试侦听器:

    请注意,AspectJ注释
    @declareReceidence(“RetryInterceptor,*”)
    表示此拦截器将在任何其他拦截器之前执行。请在两个拦截器类上用
    @Order
    注释替换它。否则,
    @Around
    通知无法捕获节流拦截器引发的异常

    同样值得一提的是,这个拦截器不需要任何反射来实现重试逻辑,它直接使用重试循环中的连接点来重试
    thisJoinPoint.continue()
    。这可以很容易地分解到实现不同重试行为的helper方法或helper类中。只需确保使用
    ProceedingJoinPoint
    作为参数,而不是
    Callable

    package de.scrum\u master.aspect;
    导入org.aspectj.lang.ProceedingJoinPoint;
    导入org.aspectj.lang.annotation.Around;
    导入org.aspectj.lang.annotation.Aspect;
    导入org.aspectj.lang.annotation.declareReceidence;
    导入de.scrum_master.app.ThrottlingException;
    @面貌
    @申报受理(“复验受理人,*”)
    公共类重试接收器{
    私有静态int MAX_trys=5;
    私有静态int WAIT_MILLIS_尝试之间=1000;
    @围绕(“执行(*doSomething())”)
    公共对象调用(ProceedingJoinPoint thisJoinPoint)抛出Throwable{
    System.out.println(getClass().getSimpleName()+“->”+此连接点);
    ThrottlingException ThrottlingException=null;
    对于(int i=1;i执行(void de.scrum\u master.app.Application.doSomething())
    ThrottlingInterceptor->执行(void de.scrum_master.app.Application.doSomething())
    在try#1期间节流
    ThrottlingInterceptor->执行(void de.scrum_master.app.Application.doSomething())
    在try#2期间节流
    ThrottlingInterceptor->执行(void de.scrum_master.app.Application.doSomething())
    做某事
    
    重试失败的控制台日志:

    RetryInterceptor->execution(void de.scrum\u master.app.Application.doSomething())
    ThrottlingInterceptor->执行(void de.scrum_master.app.Application.doSomething())
    在try#1期间节流
    ThrottlingInterceptor->执行(void de.scrum_master.app.Application.doSomething())
    在try#2期间节流
    ThrottlingInterceptor->执行(void de.scrum_master.app.Application.doSomething())
    在try#3期间被限制
    ThrottlingInterceptor->执行(void de.scrum_master.app.Application.doSomething())
    在try#4期间节流
    ThrottlingInterceptor->执行(void de.scrum_master.app.Application.doSomething())
    try#5时节流
    线程“main”de.scrum\u master.app.ThrottlingException中的异常:调用已限制
    在de.scrum_master.aspect.ThrottlingInterceptor.invoke(ThrottlingInterceptor.aj:19)
    在de.scrum_master.app.Application.doSomething_中,在body0(Application.java:9)附近
    在de.scrum\u master.app.Application.doSomething\u aroundBody1$advice(Application.java:22)
    在de.scrum_master.app.Application.doSomething(Application.java:1)
    位于de.scrum_master.app.Application.main(Application.java:5)
    
    请随时提出与我的答案相关的任何后续问题


    更新:我不知道该怎么做
    <bean id="retryInterceptor" class="com.company.xyz.RetryInterceptor">
        <constructor-arg index="0"><ref bean="retryPolicy"/></constructor-arg> 
    </bean>
    
    
    <bean id="throttlingInterceptor" class="com.company.xyz.ThrottlingInterceptor">
        <constructor-arg><value>throttleKey</value></constructor-arg> 
    </bean>
    <context:component-scan base-package="com.company.xyz">
      <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
    </context:component-scan>
    <aop:aspectj-autoproxy/>