Java Spring AOP-正确配置重试建议
我是SpringAOP新手,一直在做一些实验 我正试图通过SpringAOP为我的一个项目设置重试和速率限制。 用例如下所示:-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
ThrottledException
节流异常
,重试
@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/>