简体   繁体   English

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

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

I want to have annotation on class level that will execute advice on every method in annotated class.我想在 class 级别上有注释,它将对注释 class中的每个方法执行建议。 Is that even possible.这还可能吗。

Example: I would like to annotate OmniDemoService with @DoSomethingForMe and I want both method1 and method2 to log " look at me " before execution示例:我想用@DoSomethingForMe注释OmniDemoService并且我希望method1method2在执行前记录“看我

This example is not working and I don't know why.这个例子不起作用,我不知道为什么。 When I transform Pointcut to Around and just use it with annotation (also change annotation ElementType to method) everything is working on method level.当我将 Pointcut 转换为 Around 并将其与注释一起使用时(还将注释 ElementType 更改为方法),一切都在方法级别上工作。 So I think it is wrong defined Pointcut.所以我认为这是错误定义的切入点。

Annotation:注解:

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

Advice:建议:

@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");
    }
}

Usage:用法:

@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---");
    }
}

Your issue is that you are confusing pointcut definition with advices.您的问题是您将切入点定义与建议混淆了。

Pointcut is aiming, advice performs the actual WhateverYouWantToBeExecuted. Pointcut 是瞄准,advice 执行实际的 WhatYouWantToBeExecuted。 Like for example比如像

@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);
}

Check out what the AspectJ quick reference says about @annotation() :查看AspectJ 快速参考中关于@annotation()的内容:

any join point where the subject has an annotation of type SomeAnnotation主题具有SomeAnnotation类型注释的任何连接点

You used @annotation(DoSomethingForMe) but the " subject " of a method execution is a method .您使用@annotation(DoSomethingForMe)但方法执行的“ 主题”是方法 So that would mean any method annotated @DoSomethingForMe.所以这意味着任何注释@DoSomethingForMe的方法。

Use @this(DoSomethingForMe) or @target(DoSomethingForMe) .使用@this(DoSomethingForMe)@target(DoSomethingForMe)

Thanks to kriegaex for pointing out that @this and @target must be evaluated at runtime, which would pollute the codebase a lot (ie check in every method).感谢kriegaex指出必须在运行时评估@this@target ,这会严重污染代码库(即检查每个方法)。 So the next approach is better:所以下一个方法更好:


If you check the AspectJ manual section about type patterns you will see that you can annotate the type directly.如果你查看 AspectJ 手册中关于类型模式的部分,你会发现你可以直接注释类型。 Please also remember to use use fully qualified class names.还请记住使用完全限定的 class 名称。 So that would be:所以那将是:

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

Also, if you have such a simple pointcut and you don't need to reuse it, I think you can drop the additional method and just use it in the advice directly:另外,如果你有这么简单的切入点并且不需要重用它,我认为你可以放弃附加方法,直接在建议中使用它:

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

which says: "before the execution of any public method of a type annotated with @com.path.DoSomethingForMe ", where "before the execution of a method" means "inside the method, at the beginning".它说:“在执行带有@com.path.DoSomethingForMe注释的类型的任何公共方法之前”,其中“在方法执行之前”的意思是“在方法内部,在开始时”。


Alternatively, if this pointcut looks a bit too complicated for you, you can separate annotation matching and method matching like this, as suggested by J Asgarov in his comment:或者,如果这个切入点对您来说有点过于复杂,您可以像这样将注释匹配和方法匹配分开,正如J Asgarov在他的评论中所建议的那样:

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

Solution for the problem is to use within for pointcut该问题的解决方案是使用within for pointcut

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

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

Solution provided by @J Asgarov in the comments @J Asgarov 在评论中提供的解决方案

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

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