【问题标题】:Incorporating Guice and AOP结合 Guice 和 AOP
【发布时间】:2020-09-12 10:36:34
【问题描述】:

我正在构建一个包,它试图根据标志截取函数的返回值。我的设计涉及一些 AOP。这个想法是一个类FirstIntercept拦截一个调用firstCall并将参数存储在Parameters对象中。然后稍后,第二个类 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
   }
}

我想要实现的是Parameters 对象在通过AOP 调用FirstIntercept.loadParam 时一劳永逸地加载。我不太确定我该如何坚持这种坚持。我在网上看了看,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 正在运行,但没有调用调用。

【问题讨论】:

    标签: java aop guice


    【解决方案1】:

    如果您扩展 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 用 @AfterReturn 和 FirstInterceptor 包装一个方法
    2. 然后你调用interceptor.firstCall()

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

    我猜你是否打过电话:

    intercept.loadParam();
    

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

    编辑 不好了。看看这一行

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

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

    【讨论】:

    • 我在FirstInterceptor 中添加了invoke 方法,但即使@AfterReturning 注释方法被调用,它也不会被调用。我确保实例化 Guice.createInjector(new InterceptionModule()) 并使用 injector.getInstance(FirstInterceptor.class)
    • 阅读AOP上的规则,不能是private,final等。另外,我不知道你在哪里使用injector.getInstance()。为了提供更好的细节,我需要查看更多/所有代码。
    • 您正在调用未使用 @AfterReturning 注释的方法。如果您希望拦截器拦截所有类方法,只需切换匹配器并将注释放在类上。但请确保添加 Service 类,切勿使用相同的拦截器包装拦截器类。
    • 哦,我想只要有@AfterReturning注释的方法,invoke就会被调用。我很困惑:我永远不会直接调用intercept.loadParam(),因为只有在调用firstCall() 时才会触发loadParam()
    • 你是对的。任何带有@afterretuening 注释的方法都会被调用。位您没有调用 loadParam。你打电话给firstcall。 FirstCall 没有注释。 LoadParam 是。那么为什么 firstParam 会触发它呢?您需要将注解移至 firstcall 方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    相关资源
    最近更新 更多