繁体   English   中英

为 Spring AOP 注释创建切入点,将注释放在 class 上,并对 class 中的每个方法执行建议

[英]Create Pointcut for Spring AOP annotation to put annotation on class and execute advice on every method in class

我想在 class 级别上有注释,它将对注释 class中的每个方法执行建议。 这还可能吗。

示例:我想用@DoSomethingForMe注释OmniDemoService并且我希望method1method2在执行前记录“看我

这个例子不起作用,我不知道为什么。 当我将 Pointcut 转换为 Around 并将其与注释一起使用时(还将注释 ElementType 更改为方法),一切都在方法级别上工作。 所以我认为这是错误定义的切入点。

注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DoSomethingForMe {
}

建议:

@Aspect
@Component
public class DoSomethingForMeAdvice {

    private static final Logger logger = LoggerFactory.getLogger(DoSomethingForMeAdvice.class);

    @Pointcut("execution(public * *(..)) && @annotation(DoSomethingForMe)")
    public void anyAnnotatedMethod() {
    }

    @Before("anyAnnotatedMethod()")
    public void acquireExecution() {
        logger.info("look at me");
    }
}

用法:

@Service
@DoSomethingForMe
public class OmniDemoService {

    private static final Logger logger = LoggerFactory.getLogger(OmniDemoService.class);

    public void method1() {
            logger.info("---1---");
    }
    
    public void method2() {
            logger.info("---2---");
    }
}

您的问题是您将切入点定义与建议混淆了。

Pointcut 是瞄准,advice 执行实际的 WhatYouWantToBeExecuted。 比如像

@Pointcut("@annotation(com.omnidemo.advice.DoSomethingForMe)")
public void anyAnnotatedMethod() {
}


@Before("anyAnnotatedMethod()")
public void logMethodCall(JoinPoint jp) {
    String methodName = jp.getSignature().toShortString();
    logger.info("Executing: " + methodName);
}

查看AspectJ 快速参考中关于@annotation()的内容:

主题具有SomeAnnotation类型注释的任何连接点

您使用@annotation(DoSomethingForMe)但方法执行的“ 主题”是方法 所以这意味着任何注释@DoSomethingForMe的方法。

使用@this(DoSomethingForMe)@target(DoSomethingForMe)

感谢kriegaex指出必须在运行时评估@this@target ,这会严重污染代码库(即检查每个方法)。 所以下一个方法更好:


如果你查看 AspectJ 手册中关于类型模式的部分,你会发现你可以直接注释类型。 还请记住使用完全限定的 class 名称。 所以那将是:

execution(public * (@com.path.DoSomethingForMe *).*(..))

另外,如果你有这么简单的切入点并且不需要重用它,我认为你可以放弃附加方法,直接在建议中使用它:

@Before("execution(public * (@com.path.DoSomethingForMe *).*(..))")

它说:“在执行带有@com.path.DoSomethingForMe注释的类型的任何公共方法之前”,其中“在方法执行之前”的意思是“在方法内部,在开始时”。


或者,如果这个切入点对您来说有点过于复杂,您可以像这样将注释匹配和方法匹配分开,正如J Asgarov在他的评论中所建议的那样:

@Before("execution(public * *(..)) && @within(com.path.DoSomethingForMe)")

该问题的解决方案是使用within for pointcut

@Pointcut("@within(DoSomethingForMe)")
public void anyAnnotatedMethod() {
}

@Before("anyAnnotatedMethod()")
public void acquireExecution() {
    logger.info("look at me");
}

@J Asgarov 在评论中提供的解决方案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM