为Spring AOP注释创建Pointcut,以将注释放在类上,并对类中的每个方法执行建议

问题描述

我想在类级别具有注释 ,以便在带注释的类中的每个方法上执行建议。 甚至有可能。

示例:我想用OmniDemoService注释@DoSomethingForMe,并且我希望 method1 method2都记录“ em>在执行之前先看看我”

此示例不起作用,我也不知道为什么。当我将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---");
    }
}

解决方法

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

切入点是瞄准目标,建议执行实际的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 quick reference@annotation()的评价:

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

您使用了@annotation(DoSomethingForMe),但是方法执行的“ subject”是方法。因此,这意味着 any 注释为@DoSomethingForMe的方法。

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

感谢kriegaex指出必须在运行时对@this@target进行评估,这会污染代码库很多(即,检查每个方法)。因此,下一种方法更好:


如果您查看关于type patterns的AspectJ手册部分,将会看到可以直接注释类型。还请记住使用完全限定的类名。这样就可以了:

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

此外,如果您有一个简单的切入点并且不需要重用它,我想您可以删除其他方法,并直接在建议中使用它:

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

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


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

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

该问题的解决方案是在切入点中使用

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

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

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

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...