Java springaop:aspect@Around不';行不通

Java springaop:aspect@Around不';行不通,java,aop,spring-aop,Java,Aop,Spring Aop,我已经使用Spring Boot和Spring Initializer制作了一个简单的web应用程序,并尝试使用@Around建议编写@Aspect 当我将我的自定义注释添加到控制器的端点方法时,它起作用,但当我将此注释添加到控制器的端点方法时,它不起作用。我花了很多时间来理解这种行为的原因,但没有任何结果。所以请帮忙 位于此处的项目: @方面 @组成部分 公共最终类MethodRepeater{ @关于(“执行(**(..)&&&@注释(RetryOnFailure)”) 公共对象换行(最终处

我已经使用Spring Boot和Spring Initializer制作了一个简单的web应用程序,并尝试使用@Around建议编写@Aspect

当我将我的自定义注释添加到控制器的端点方法时,它起作用,但当我将此注释添加到控制器的端点方法时,它不起作用。我花了很多时间来理解这种行为的原因,但没有任何结果。所以请帮忙

位于此处的项目:

@方面
@组成部分
公共最终类MethodRepeater{
@关于(“执行(**(..)&&&@注释(RetryOnFailure)”)
公共对象换行(最终处理joinPoint joinPoint)抛出可丢弃{
//代码在这里
}
}
因此,我的目标是:

@RequestMapping
公共字符串索引(){
inTry();
返回“OK”;
}
@RetryOnFailure(尝试次数=3,延迟=2,单位=TimeUnit.s)
公共文件{
抛出新的RuntimeException(“try中的异常”+++计数器);
}

我遇到了一个类似的问题,我使用AspectJ解决了这个问题:


另外-我花了一些时间才发现,我的想法没有正确地重建方面,因此在您尝试一些更激进的措施之前,可能值得尝试清理/重建项目。

您犯了一个典型的Spring AOP初学者错误:您忘了基于代理的AOP只有在从外部调用代理方法时才有效,不通过
(避免代理)。但是内部调用
inTry()
this.inTry()
相同。因此,aspect不会触发
inTry
,您必须像这样重新排列代码:

package spring.aop;
导入org.springframework.web.bind.annotation.RequestMapping;
导入org.springframework.web.bind.annotation.RestController;
导入java.util.concurrent.TimeUnit;
@RestController(“/”)
公共类家庭控制器{
静态整数计数器=0;
@请求映射
@RetryOnFailure(尝试次数=3,延迟=2,单位=TimeUnit.s)
公共字符串索引(){
抛出新的RuntimeException(“try中的异常”+++计数器);
}
}
我也改变了一点方面,以便

  • 避免反射,并通过
    @annotation()
    将注释直接绑定到通知参数
  • 在触发通知时记录连接点,然后
  • 在try#3上返回“OK”(只是为了好玩,不需要)
package spring.aop;
导入org.aspectj.lang.ProceedingJoinPoint;
导入org.aspectj.lang.annotation.Around;
导入org.aspectj.lang.annotation.Aspect;
导入org.springframework.stereotype.Component;
@面貌
@组成部分
公共最终类MethodRepeater{
@大约(“执行(*spring.aop..*(..))&&&&@annotation(retryOnFailure)”)
公共对象包装(最终处理joinPoint joinPoint,RetryOnFailure RetryOnFailure)抛出可丢弃的{
系统输出打印LN(连接点);
返回继续(连接点、retryOnFailure);
}
私有对象继续(ProceedingJoinPoint、RetryOnFailure、RetryOnFailure)抛出可丢弃的{
int尝试=1;
while(true){
试一试{
返回joinPoint.procedure();
}捕获(最终可丢弃ex){
System.out.println(“Try#”+trust+”失败:“+ex”);
如果(++trument>=retryOnFailure.truments())
返回“OK”;
如果(retryOnFailure.delay()>0L)
retryOnFailure.unit().sleep(retryOnFailure.delay());
}
}
}
}
现在它工作了,控制台日志显示:

执行(字符串spring.aop.HomeController.index())
Try#1失败:java.lang.RuntimeException:Try 1中的异常
Try#2失败:java.lang.RuntimeException:Try 2中的异常

inTry()
始终引发异常。这有什么意义吗?只是举个例子。我有一个真正的项目,在需要的地方。如果某些外部资源不可用,则需要实现“重试”功能。因此,您需要注意,缺少aspectj maven插件中存在的问题?如果我添加aspectj maven插件,它会正常工作。非常感谢您的回答,但这是编译时编织,我尝试实现纯SpringAOP运行时编织。不,那不是解决办法。AspectJ Maven插件用于完整的AspectJ编译时或后续加载时编织。对于基于代理的SpringAOP,这绝对不是必需的。如果它对您的情况有帮助的话,那么仅仅是因为您隐式地从Spring AOP切换到AspectJ,而不是解决问题,而是避免真正的问题。您还可以尝试在切入点中用包写出注释的名称:@Around(“execution(**(..)&@annotation(com.my.package.RetryOnFailure)”@MatthiasDanetzky,非常感谢。我决定,由于应用程序设计的原因,我将切换到编译时编织。谢谢非常感谢你的解释。是的,你说得对。问题的重点是“为什么?!”,你描述得很好。干杯