【问题标题】:advice is not executing if the annotations contains parameters如果注解包含参数,建议不会执行
【发布时间】:2021-09-02 10:44:33
【问题描述】:

我正在尝试获得一些建议来执行。 当我使用不带参数的注释时,它会执行,但当注释包含参数时,它不会执行。

@Aspect
class  a{   
    @Pointcut("execution(@com.annotations.AnnotationName* *(..))")
    void someMethod() {}

    @Around("someMethod()")
    public Object aroundSomeMethod(ProceedingJoinPoint pjp) throws Throwable
    {
    // some code
    }
}

注释:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationName
{
    public String someString();
    public boolean someBoolean();
}

注解的使用:

@AnnotationName(
        someString= "string",
        someBoolean = false
)
private void mycode()
{//code }

【问题讨论】:

  • 您确定您的切入点定义正确吗?我自己尝试过,我得到:java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting 'name pattern' at character position 54 execution(@com.annotations.AnnotationName* *(..))
  • 这不是我真正使用的表达式,无法写出真正的路径。但它确实在没有参数的情况下工作
  • 如果您不发布真实代码,我们如何为您提供帮助?请发布一个有意义的小例子来复制行为。
  • 注解参数的数量不是问题,而是你试图建议一个私有方法,这对于像 Spring AOP 这样的基于代理的工具是不可能的。您需要本地 AspectJ 来为私有方法提供建议。
  • 请提供足够的代码,以便其他人更好地理解或重现问题。

标签: spring aop spring-aop spring-annotations


【解决方案1】:

以下方面代码将建议使用@AnnotationName 注释的目标方法

@Component
@Aspect
public class SomeMethodAspect {

    @Pointcut("@annotation(annotationName) && within(so.qn69016852..*)")
    private void someMethod(AnnotationName annotationName) {}
    
    @Around("someMethod(annotationName)")
    public Object aroundSomeMethod(ProceedingJoinPoint pjp,AnnotationName annotationName) throws Throwable
    {
        System.out.println(annotationName.someString());
        System.out.println(annotationName.someBoolean());
        return pjp.proceed();
    }
}

一些更正/观察。

  1. Spring AOP 不能建议 Spring bean 的私有方法。 mycode() 方法应该在 bean 中并且最好是公开的。 (Refer)
  2. Aspect 也应该是 spring bean。这可以通过使用@Component 注释方面来实现

记得限制范围:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#writing-good-pointcuts

您还可以通过@kriegaex 的answer 了解为什么@annotation 具有全局范围。

更新:

OP 共享的代码也适用于修改错字(切入点表达式中AnnotationName* 之间的空格)。之前分享的观察结果在这里也适用。

@Component
@Aspect
public class SomeMethodAspect {

    @Pointcut("execution(@so.qn69016852.anno.AnnotationName * so.qn69016852..*.*(..))")
    private void someMethod() {}
    
    @Around("someMethod() && @annotation(annotationName)")
    public Object aroundSomeMethod(ProceedingJoinPoint pjp,AnnotationName annotationName) throws Throwable
    {
        System.out.println(annotationName.someBoolean());
        System.out.println(annotationName.someString());
        return pjp.proceed();
    }
}

【讨论】:

  • 虽然这是对如何使用 Spring AOP 拦截 annotatd 方法的问题的正确答案,但它并没有解决原始问题中提出的 OP 问题(建议私有方法)。请参阅我在问题下的评论。
  • 我的假设是,这不是实际代码(OP 在他的评论中暗示了相同的内容),问题出在 spring-aop 上。我同意你在 cmets 关于建议私有方法的意见,我在这个答案中确实提到了这一点。感谢您指出。
  • 哦,对不起,我没有注意到你的答案中间关于私有方法的评论。我认为 OP 只发布了一个虚假的切入点,而是一个实际的目标方法。为什么他在复制粘贴时要手动将public改为private?所以这才是真正的问题。他只是碰巧在该方法的注释中使用了参数,错误地认为这是问题的根本原因,即使它完全不相关。
  • @kriegaex 那么你如何解释没有参数,即使方法是私有的,建议也会执行?
  • 我不解释,因为使用 Spring AOP 是不可能的。您要么误解了您的日志,要么在不知不觉中使用了原生 AspectJ。
猜你喜欢
  • 2015-04-03
  • 2018-08-23
  • 2013-07-03
  • 1970-01-01
  • 2016-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-23
相关资源
最近更新 更多