Spring子类中自定义注释的AOP切入点表达式

时间:2015-06-25 10:20:37

标签: java spring aspectj spring-aop pointcut

我正在开发一个日志方面,需要拦截所有使用自定义注释注释的类和方法。

下面是自定义注释类,可以在类和方法上进行注释:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Loggable {
    LogLevel value();
}

我使用这些切入点表达式来拦截带注释@Loggable的方法和类,它适用于所有简单类,但不适用于扩展或实现的类。

//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) {
  ..
  ..
}

以下是超类

的代码
@Component
@Loggable(LogLevel.INFO)
public abstract class Processor{
  public void process(){
      readProcess();
  }

  public abstract void readProcess();
}

以下是子类

的代码
@Service
@Loggable(LogLevel.INFO)
public class MyServiceProcessor extends Processor {

  @Override
  public void readProcess(){
    ...
    ...
  }
}

通过执行

调用应用程序readProcess()
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();

即使@LoggableProcessor上有MyServiceProcessor,但在调用readProcess时,也不会调用建议。

但是为process()而不是readProcess调用了建议。

当在任何类或方法上应用注释@Logabble时,如何编写切入表达式,该表达式也会拦截对任何子类方法的调用?

1 个答案:

答案 0 :(得分:0)

嗯,首先这个

@Pointcut("execution(* *(..)) &&  within(@com.logger.Loggable *)")
public void classAnnotationLogger() {}

只是一个切入点,而不是一个建议,所以除非你有一个实际使用这个切入点的建议,否则它什么都不做。你还没有发表这样的建议,所以我只能推测。

其次,您没有提供任何由

触发的示例代码
@Before(value = "@annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {}

完全没有注释方法。您的示例代码仅显示带注释的类。

对于子类的@Loggable注释,它不应该是必需的,因为它的基类已经带有相同的注释,注释是@Inherited。这适用于类上的注释,但不适用于方法或接口上的注释,请参阅my other answer以获取解释和可能的解决方法。

你的这个例子实际上应该有效,我看不出它为什么不会这样做的原因:

Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();

但是对readProcess()(相当于this.readProcess())的内部调用无效:

public void process() {
    readProcess();
}

这是因为Spring AOP是一个基于代理的“AOP lite”框架,它依赖于JDK动态代理(用于接口)或CGLIB代理(用于类)。但是对this.someMethod()的调用不会通过任何类型的代理进行路由,因此Spring方面无法拦截它们。这是记录在案的行为。如果您想克服此限制并将方面应用于内部方法调用,请使用成熟的AspectJ,如文档here所述。