Java CDI。拦截器仅在 class 中的第一个方法调用中被调用

Java CDI. Interceptor is only invoked in the first method call in a class

我正在使用 CDI 拦截器,我意识到只有 class 中用 @Interceptor 注释的第一个方法调用被拦截。在下面的示例中,方法 B 永远不会被拦截。

@InterceptorBinding
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {

}


@Transactional
@Interceptor
public class TransactionsInterceptor {

    @AroundInvoke
    public Object transactionInterceptor(InvocationContext context) throws Exception {

          System.out.println("Method="+context.getMethod().getName());
          return context.proceed();

    }
}


public Interface AnImportantInterface {
      public void methodA();
      public void methodB();
}

@Transactional
@ThreadScoped
public class AnImportantClass implements AnImportantInterface {

    public void methodA() {

        methodB();
    }

    public void methodB() {

        //This method is never intercepted
    }

}


public class AnotherImportantClass {
    @Inject AnImportantInterface aui;

    public void someMethod() {
        aui.methodA();
    }
}

如果先调用methodA,如何实现methodB被拦截?有什么解决方法吗?

这是因为您是直接调用 methodB() 而不是通过 CDI 代理,因此永远不会调用拦截器。只有在使用其代理调用 CDI bean 方法时才会调用拦截器。您应该将方法 B 移动到另一个 CDI bean 中,并将其 @Inject 移动到这个 bean 中,然后从 methodAmethodB() 更改为 bean2.methodB(..).

使用自我注入。 Bean 自注入可以很容易地在 CDI 中实现——只需注入一个实例,其中 T 是实现。

@Named
public class Foo implements Fooable{

@Inject

private Instance<Foo> foo;

public void executeFirst(){

foo.get().executeSecond();

}

@Transactional

public void executeSecond(){

//do something

}

}

这样,您就可以在同一个 bean 中执行您的方法。如果 bean 是有状态的,请确保 select 正确的范围。还要确保实例的通用类型 T 直接是实现 - 这确保每次都实现正确的对象。