Spring 子类中自定义注解的AOP切入点表达式
Spring AOP Pointcut expression for custom annotation in subclass
我正在处理日志方面的工作,它需要拦截所有使用自定义注释注释的 classes 和方法。
下面是自定义注释class,可以在class和方法上进行注释:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Loggable {
LogLevel value();
}
我正在使用这些切入点表达式来拦截方法和带有注释 @Loggable
的 classes, 它适用于所有简单的 classes 但不为扩展或实施的 classses 工作。
//Works for annotation @Loggable on class level
@Pointcut("execution(* *(..)) && within(@com.logger.Loggable *)")
public void classAnnotationLogger() {
}
//Working for methods annotated with @Loggable
@Before(value = "@annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {
..
..
}
下面是超级代码class
@Component
@Loggable(LogLevel.INFO)
public abstract class Processor{
public void process(){
readProcess();
}
public abstract void readProcess();
}
下面是subclass
的代码
@Service
@Loggable(LogLevel.INFO)
public class MyServiceProcessor extends Processor {
@Override
public void readProcess(){
...
...
}
}
在应用程序中 readProcess()
被调用
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();
即使我在 Processor
和 MyServiceProcessor
上有 @Loggable
,当 readProcess
被调用时,建议没有被调用。
但是为 process()
而不是 readProcess
调用了建议。
当注释 @Logabble
应用于任何 class 或方法时,如何编写切入点表达式,它也拦截对任何子class 方法的调用?
嗯,首先这个
@Pointcut("execution(* *(..)) && within(@com.logger.Loggable *)")
public void classAnnotationLogger() {}
只是一个切入点而不是一个建议,所以它不会做任何事情,除非你也有一个实际使用这个切入点的建议。你没有发布这样的建议,所以我只能推测。
其次,您没有提供任何将由
触发的示例代码
@Before(value = "@annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {}
完全没有,即没有注释方法。您的示例代码仅显示带注释的 classes.
至于subclass上的@Loggable
注解,应该不需要,因为它的baseclass已经带有相同的注解,而注解是@Inherited
.这适用于 classes 上的注释,但不适用于方法或接口上的注释,请参阅 了解解释和可能的解决方法。
你的这个例子应该确实有效,我看不出为什么它不起作用:
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();
但是这个对 readProcess()
的内部调用(相当于 this.readProcess()
)将不起作用:
public void process() {
readProcess();
}
这是因为 Spring AOP 是一个基于代理的 "AOP lite" 框架依赖于 JDK 动态代理(用于接口)或 CGLIB 代理(用于 classes) .但是对 this.someMethod()
的调用不会通过任何类型的代理进行路由,因此它们不会被 Spring 方面拦截。这是记录在案的行为。如果您想克服此限制并将方面也应用于内部方法调用,请使用完整的 AspectJ,如文档所述 here.
我正在处理日志方面的工作,它需要拦截所有使用自定义注释注释的 classes 和方法。
下面是自定义注释class,可以在class和方法上进行注释:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Loggable {
LogLevel value();
}
我正在使用这些切入点表达式来拦截方法和带有注释 @Loggable
的 classes, 它适用于所有简单的 classes 但不为扩展或实施的 classses 工作。
//Works for annotation @Loggable on class level
@Pointcut("execution(* *(..)) && within(@com.logger.Loggable *)")
public void classAnnotationLogger() {
}
//Working for methods annotated with @Loggable
@Before(value = "@annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {
..
..
}
下面是超级代码class
@Component
@Loggable(LogLevel.INFO)
public abstract class Processor{
public void process(){
readProcess();
}
public abstract void readProcess();
}
下面是subclass
的代码@Service
@Loggable(LogLevel.INFO)
public class MyServiceProcessor extends Processor {
@Override
public void readProcess(){
...
...
}
}
在应用程序中 readProcess()
被调用
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();
即使我在 Processor
和 MyServiceProcessor
上有 @Loggable
,当 readProcess
被调用时,建议没有被调用。
但是为 process()
而不是 readProcess
调用了建议。
当注释 @Logabble
应用于任何 class 或方法时,如何编写切入点表达式,它也拦截对任何子class 方法的调用?
嗯,首先这个
@Pointcut("execution(* *(..)) && within(@com.logger.Loggable *)")
public void classAnnotationLogger() {}
只是一个切入点而不是一个建议,所以它不会做任何事情,除非你也有一个实际使用这个切入点的建议。你没有发布这样的建议,所以我只能推测。
其次,您没有提供任何将由
触发的示例代码@Before(value = "@annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {}
完全没有,即没有注释方法。您的示例代码仅显示带注释的 classes.
至于subclass上的@Loggable
注解,应该不需要,因为它的baseclass已经带有相同的注解,而注解是@Inherited
.这适用于 classes 上的注释,但不适用于方法或接口上的注释,请参阅
你的这个例子应该确实有效,我看不出为什么它不起作用:
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();
但是这个对 readProcess()
的内部调用(相当于 this.readProcess()
)将不起作用:
public void process() {
readProcess();
}
这是因为 Spring AOP 是一个基于代理的 "AOP lite" 框架依赖于 JDK 动态代理(用于接口)或 CGLIB 代理(用于 classes) .但是对 this.someMethod()
的调用不会通过任何类型的代理进行路由,因此它们不会被 Spring 方面拦截。这是记录在案的行为。如果您想克服此限制并将方面也应用于内部方法调用,请使用完整的 AspectJ,如文档所述 here.