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 ()付款经理 付款获得批准后。 当任务完成时,我们从任务管理器的方法调用taskComplete()发送电子邮件。

我必须找出触发发送电子邮件的事件。

我在付款管理器的paymentApproved ()上应用了自定义注释@EVENT("PAYMENT"),并在任务管理器的方法上应用了@EVENT("TASK")taskComplete()注释。

我怎样才能logEmail(JoinPoint joinPoint)方面获得@EVENT的价值。

脚手架:

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

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() {}
}

方面:

您的切入点想要表达:在由@Event注释的方法的控制流中捕获用@Loggable注释的方法。控制流可以通过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精简版",不支持call()

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

@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("******");
}

最新更新