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

问题描述 投票:0回答:2
@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()
上有一个带有自定义注释的切入点。

这个方法

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

就像我们在付款被批准时从 paymentManager 的

paymentApproved ()
方法调用 sendEmail 一样。 当任务完成时,我们从 taskManger 的
taskComplete()
方法调用 sendEmail。

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

我在 paymentManager 的

@EVENT("PAYMENT")
上应用了自定义注释
paymentApproved ()
,在 taskManger 的
@EVENT("TASK")
方法上应用了
taskComplete()

如何在

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

spring aop aspectj spring-aop
2个回答
3
投票

脚手架:

对不起,我不喜欢全大写的类名,我也用了我自己的包名作为例子,因为我的模板已经生成了它们。

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
s.

另请注意,在一种情况下,

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
注释的方法。控制流可以用
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()
.


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("******");
}
© www.soinside.com 2019 - 2024. All rights reserved.