CDI:跨不同模块/ bean归档使用拦截器

The*_*heo 16 java-ee interceptor cdi ejb-3.1

我的Java EE 6应用程序由war文件和ejb模块组成,包含在ear文件中.我正在使用CDI for DI(即我在两个模块中都有一个beans.xml文件).我想使用war模块中的ejb模块中定义的日志拦截器.我在ejb的beans.xml中启用了拦截器:

<beans>
    <interceptors>
        <class>com.test.interceptor.LoggingInterceptor</class>
    </interceptors>
</beans>
Run Code Online (Sandbox Code Playgroud)

这仅适用于使用ejb模块中的拦截器注释的类.战争模块中的类不被截获(尽管它们也被拦截器注释).我认为解决方案是在战争的拦截器中启用拦截器(如上所述).但是无法使用以下消息部署应用程序:

严重:加载应用程序时出现异常:WELD-001417启用拦截器类类com.test.interceptor.LoggingInterceptor既没有注释@Interceptor也没有通过可移植扩展注册

我的LoggingInterceptor看起来像这样:

@Log
@Interceptor
public class LoggingInterceptor {
    private static final Logger logger =  Logger.getLogger(LoggingInterceptor.class.getName());

    static {
        logger.setLevel(Level.ALL);
    }

    @AroundInvoke
    public Object logMethod(InvocationContext ctx) throws Exception {
        logger.log(Level.FINE, "ENTRY {0} {1}",
                new Object[]{ ctx.getTarget().getClass().getName(), ctx.getMethod().getName() });
        long startTime = System.nanoTime();
        try {
            return ctx.proceed();
        } finally {
            long diffTime = System.nanoTime() - startTime;
            logger.log(Level.FINE, "RETURN {0} {1}",
                new Object[]{ ctx.getTarget().getClass().getName(), ctx.getMethod().getName() });
            logger.log(Level.FINE, "{0} took {1} ms", new Object[]{ ctx.getMethod(),
                    TimeUnit.MILLISECONDS.convert(diffTime, TimeUnit.NANOSECONDS)});
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

和拦截器绑定:

@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Log {}
Run Code Online (Sandbox Code Playgroud)

如何在两个模块中使用拦截器?

gor*_*tiz 10

J2EE 7规范说(参考):

您在beans.xml文件中指定的拦截器仅适用于同一存档中的类.使用@Priority批注为包含多个模块的应用程序全局指定拦截器

该解决方案具有独立于供应商的优势.

一个例子:

@Logged
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class LoggedInterceptor implements Serializable { ... }
Run Code Online (Sandbox Code Playgroud)


Dmi*_*try 5

现在为时已晚,但如果有人仍然有这个问题.两个模块都应该由同一个类加载器加载,以便跨越不同的模块使用拦截器,至少在WebSphere 8b2中是这样.在WebSphere中,可以在管理控制台中切换此设置:应用程序>应用程序类型> WebSphere企业应用程序> [您的应用程序名称]>类加载和更新检测> WAR类加载器策略=应用程序的单个类加载器.
Interceptor必须仅在beans.xml中启用ONCE.

  • 即使在WebSphere中允许(和通用),也不建议将其用于JEE应用程序.由于某种原因,类加载器是分开的. (2认同)

cov*_*ner 1

我想知道您的 WAR 是否缺乏对您的 ejb-jar 的类加载器可见性?我认为理想情况下,299 个拦截器应该位于它们自己的 jar 中,对 EJB 和 Web 模块都可见,并在它们的 beans.xml 中启用。