结合 Guice 和 AOP

Incorporating Guice and AOP

我正在构建一个包,它试图根据标志拦截函数的 return 值。我的设计涉及一些 AOP。这个想法是 class FirstIntercept 拦截调用 firstCall 并将参数存储在 Parameters 对象中。然后,第二个 class SecondIntercept 拦截另一个调用 secondCall 并根据 Parameters:

中填充的内容执行一些逻辑
// pseudoish code 
public class FirstIntercept {
   private Parameters param;

   @AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
   public void loadParam(Joinpoint joinPoint, Object payload) {
      // logic handling payload returned from firstCall()
      // logic provides a Boolean flag
      this.param = new Parameters(flag);
   }
}



public class Parameters {
   @Getter
   private Boolean flag;

   public Parameters(Boolean flag) {
      this.flag = flag;
   }
}



public class SecondIntercept {
   private static Parameters params;
   
   @Around("execution(* ...secondCall(..))")
   public void handleSecondCallIntercept(ProceedingJoinPoint joinPoint) {
      // want to do logic here based on what params contains
   }
}

我想实现的是在通过AOP调用FirstIntercept.loadParam时,一次性加载Parameters对象。我不太确定如何才能坚持下去。我在网上看了看 Google guice 似乎很有前途。我相信第一步是在 Parameters 上使用依赖注入,但我真的不确定。有人可以帮我指出正确的方向吗?


编辑:

所以我尝试了这个设置:

public class FirstIntercept implements MethodInterceptor {
   public Object invoke(MethodInvocation invocation) throws Throwable {
      System.out.println("invoked!");
      return invocation.proceed();
   }

   @AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
   public void loadParam(Joinpoint joinPoint, Object payload) {
      // do stuff
   }

   public String firstCall() {
      return "hello";
   }
}

public class InterceptionModule extends AbstractModule {
   protected void configure() {
      FirstIntercept first = new FirstIntercept();
      bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class), first);
   }
}

public class FirstIterceptTest {
   @Test
   public void dummy() {
      Injector injector = Guice.createInjector(new InterceptionModule());
      FirstIntercept intercept = injector.getInstance(FirstIntercept.class);

      intercept.firstCall();
   }
}

当我执行 .firstCall() 时,我可以看到 @AfterReturning 运行 但未调用调用。

如果您扩展 AOP https://github.com/google/guice/wiki/AOP 的文档,您应该得到接近于:

的内容
public class FirstInterceptor implements MethodInterceptor {

  @Inject Parameters parameters;  // Injected with singleton Parameter

  public Object invoke(MethodInvocation invocation) throws Throwable {
    Object result = invocation.proceed();
    // your logic based on result to set parameters.setFlag()
    return result;
  }
}

然后第二个:

public class SecondInterceptor implements MethodInterceptor {

  @Inject Parameters parameters;  // Injected with singleton Parameter

  public Object invoke(MethodInvocation invocation) throws Throwable {
    boolean flag = parameters.getFlag();
    // your logic here
    return invocation.proceed(); // maybe maybe not?
  }
}

你的参数是关键,你需要确保它是线程安全的,这是另一个话题。但是要注入这些你需要:

public class InterceptionModule extends AbstractModule {
  protected void configure() {
    // Ensure there is only ever one Parameter injected
    bind(Parameter.class).in(Scopes.SINGLETON);

    // Now inject and bind the first interceptor
    FirstInterceptor firstInterceptor = new FirstInterceptor();
    requestInjection(firstInterceptor );
    bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
        firstInterceptor);

    // Now inject and bind the second interceptor
    SecondInterceptor SecondInterceptor = new SecondInterceptor ();
    requestInjection(firstInterceptor);
    bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
        SecondInterceptor);
  }
}

编辑 看看你在做什么。

  1. 你告诉 Guice 用带有 FirstInterceptor 的 @AfterReturn 包装一个方法
  2. 然后你调用 interceptor.firstCall()

第一次调用没有@AfterReturn 注解,为什么要匹配那个配置?

我猜你是否打过电话:

intercept.loadParam();

您会看到调用方法。此外,这对于测试来说非常有用,但在现实生活中,您希望服务级别 class 具有 @AfterReturn,然后将其注入到另一个将调用 LoadParam 的 Api/Job/Etc 中。

编辑 不好了。看看这一行

bindInterceptor(Matchers.any(),  // a class with this matcher
   Matchers.annotatedWith(AfterReturning.class),  // a method with this 
        firstInterceptor); 

这意味着注入器仅在 loadParams 上触发。您需要使用@AfterReturning 注释您希望引起拦截的class 方法。并且您希望 loadParams 成为调用方法。