Spring AOP - 如何获取父(调用者)方法的注释

时间:2017-03-06 08:50:05

标签: aspectj spring-aop

@Before(value="@annotation(com.aspect.Loggable)",argNames="taskId")

public void logEmail(JoinPoint joinPoint) {

    System.out.println("@Before is running!");
    System.out.println("hijacked : " + joinPoint.getSignature().getName());
    System.out.println("******");
}

我在方法sendEmail()上有一个带有自定义注释的pointCut。

此方法sendEmail()在我们的应用程序中从不同位置调用。

就像我们在付款获得批准时从paymentApproved () paymentManager方法调用sendEmail一样。 当任务完成时,我们从taskManger的taskComplete()方法调用sendEmail。

我必须找出触发sendEmail的事件。

我在paymentManager的@EVENT("PAYMENT")上应用了自定义注释paymentApproved (),在{person}工具的@EVENT("TASK")方法上应用了taskComplete()

如何在@EVENT方面获得logEmail(JoinPoint joinPoint)的价值。

2 个答案:

答案 0 :(得分:1)

<强>脚手架:

抱歉,我不喜欢全帽类名,我也使用自己的包名作为例子,因为我的模板已经生成了它们。

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {}
package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Event {
  String value();
}

驱动程序应用程序:

这是纯Java,因为我不是Spring用户。试想一下,它是一个或多个@Component

另请注意,在一个案例中sendEmail()未被@Event注释的方法调用。这不应该触发方面,只有来自注释方法的两个调用。

package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    Application application = new Application();
    application.doSomething();
    application.paymentApproved();
    application.taskComplete();
  }

  public void doSomething() {
    sendEmail();
  }

  @Event("paymentApproved")
  public void paymentApproved() {
    sendEmail();
  }

  @Event("taskComplete")
  public void taskComplete() {
    sendEmail();
  }

  @Loggable
  public void sendEmail() {}
}

<强>方面:

你的切入点想要表达:在@Loggable注释的方法的控制流程中,用@Event注释的Catch方法。控制流可以用cflow()cflowbelow()切入点表示。

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import de.scrum_master.app.Event;

@Aspect
public class LogAspect {
  @Before(
    "@annotation(de.scrum_master.app.Loggable) &&" +
    "execution(* *(..)) &&" +  // only needed for AspectJ, not for Spring AOP
    "cflow(@annotation(event))"
  )
  public void logEmail(JoinPoint thisJoinPoint, Event event) {
    System.out.println(thisJoinPoint + " -> " + event);
  }
}

控制台日志:

execution(void de.scrum_master.app.Application.sendEmail()) -> @de.scrum_master.app.Event(value=paymentApproved)
execution(void de.scrum_master.app.Application.sendEmail()) -> @de.scrum_master.app.Event(value=taskComplete)

更新:如果您使用完整的AspectJ(例如通过加载时编织)而不是Spring AOP,您可以使用call()切入点并从那里获得封闭的连接点静态信息。然后不需要@Event注释。但Spring AOP只是“AOP lite”而不支持call()

答案 1 :(得分:0)

您可以访问接收它的注释作为参数。像这样:

@Before(value="@annotation(EVENT)",argNames="taskId")

public void logEmail(JoinPoint joinPoint, Event event) {

    // do what you need with event. For example, if the field is called value you can do this:
    if ("PAYMENT".equals(event.value())) {
       // do sth
    }

    System.out.println("@Before is running!");
    System.out.println("hijacked : " + joinPoint.getSignature().getName());
    System.out.println("******");
}