annotations - Spring 注解 AOP 调用两次

标签 annotations aop spring-aop

我使用自定义注释为我的 spring boot Controller 注释了一些功能,以用于记录目的。但是,我发现对于嵌套方法,before 建议会执行两次。在这里寻找一些想法。请引用下面的代码片段。

Controller

@RequestMapping(value = "apply")
    @OperationMILog
    public ApplyHttpResponse apply(@RequestHeader final String custId, @RequestAttribute final String cardNo,
        @RequestBody final InstallmentApplyHttpRequest installApplyReq, @PathVariable final String source) {

        //test
        this.test();  //**line 387**

...
}


 ....
     @OperationMILog
        private String test() {
            return this.test1(); //**line 593**
        }

@OperationMILog
private String test1() {
    return "test1";
}

注释

@Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface OperationMILog {

}

方面

@Aspect
public class GenericLoggingAspect {

      public static GenericLoggingAspect genericLoggingAspect;

        @PostConstruct
        public void init() {    
            genericLoggingAspect = this;
        }


    @Before("@annotation(com.mycomp.log.OperationMILog)")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("Before .........." + joinPoint.getSignature().getName());
    }

}

在 Controller 中触发应用功能时,会打印以下日志。

Before ..........apply
Before ..........test
Before ..........test
Before ..........test1
Before ..........test1

在 doBefore 函数处设置断点并在 Debug模式下查看堆栈跟踪。
打印第一个“Before …… test”时,堆栈跟踪看起来不错。
GenericLoggingAspect.doBefore(JoinPoint) line: 87   
InstallmentController.apply(String, String, InstallmentApplyHttpRequest, String) line: 387  
InstallmentController$$FastClassBySpringCGLIB$$55eeb128.invoke(int, Object, Object[]) line: not available   

当第二个“Before .......... test”将显示时,堆栈跟踪非常连线,如下所示
GenericLoggingAspect.doBefore(JoinPoint) line: 87   
InstallmentController.test() line: 593  
InstallmentController.apply(String, String, InstallmentApplyHttpRequest, String) line: 387  
InstallmentController$$FastClassBySpringCGLIB$$55eeb128.invoke(int, Object, Object[]) line: not available   

我不知道为什么第 593 行会触发 doBefore。同样的情况适用于 test1 的打印。

我的项目没有任何 XML 配置,所有配置都是在注释中完成的。

最佳答案

感谢您显示我在评论中要求的日志输出。现在我可以告诉你问题是什么:

Before ..........call(String com.mycomp.controller.InstallmentController.test())
Before ..........execution(String com.mycomp.controller.InstallmentController.test())
  • 很明显,您使用 AspectJ(可能使用 LTW),而不是 Spring AOP。为什么我可以这么说?因为Spring AOP只知道execution()连接点,而不是 call()那些。
  • 由于上面给出的原因,您的切入点为每个方法调用匹配两次:一次用于进行调用的连接点(调用者),一次用于实际执行被调用方法的连接点(被调用者)。这就是为什么您在日志中获得两个输出行的原因。
  • 所以你真正想要做的是在你的切入点中指定你到底想要拦截、调用或执行什么。建议你加&& execution(* *(..))到切入点。然后你会得到预期的结果,类似于 Spring AOP 会做的事情,即使没有添加。

  • 经验教训:AspectJ 比 Spring AOP 强大得多。您需要学习如何使用如此强大的工具,有时会故意限制其功能。 :-)

    关于annotations - Spring 注解 AOP 调用两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48683175/

    相关文章:

    复合键中的 Hibernate @GeneratedValue

    java - 如何防止 Eclipse 在将表达式分配给局部变量时生成类型注释

    unity-container - 拦截Unity 2.0 HandlerAttribute,无需接口(interface)

    java - 切入点匹配对公共(public)方法的所有调用(对 self 的调用除外)

    spring-boot - CrudRepository 接口(interface)中所有 CRUD 方法的切入点

    Spring AOP Bean 注入(inject)错误?

    java - 以编程方式启用 Spring Security pre-post-annotations

    java - 用 Java 在数据库中保存 XML 文档(Hibernate 和 JAXB 的组合)

    java - Spring 的@RequestMapping 是如何工作的?

    spring - 从 ProceedingJoinPoint 获取 java.lang.reflect.Method?