我的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>
这仅适用于使用 ejb模块中的拦截器注释的类。战争模块中的类不被截获(尽管它们也被拦截器注释)。我认为解决方案是在战争的拦截器中启用拦截器(如上所述)。但是无法使用以下消息部署应用程序:
SEVERE:加载应用程序时出现异常:WELD-001417启用拦截器类类com.test.interceptor.LoggingInterceptor既没有注释@Interceptor也没有通过可移植扩展注册
My 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)});
}
}
}
拦截器绑定:
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Log {}
如何为两个模块使用拦截器?
答案 0 :(得分:10)
J2EE 7规范说(reference):
您在beans.xml文件中指定的拦截器仅适用于 同一档案中的课程。使用@Priority批注指定 全局拦截器,用于由多个应用程序组成的应用程序 模块
此解决方案具有独立于供应商的优势。
一个例子:
@Logged
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class LoggedInterceptor implements Serializable { ... }
答案 1 :(得分:5)
现在为时已晚,但如果有人还有这个问题。
两个模块都应该由同一个类加载器加载,以便跨越不同的模块使用拦截器,至少在WebSphere 8b2中是这样。
在WebSphere中,可以在管理控制台中切换此设置:应用程序&gt;应用类型&gt; WebSphere企业应用程序&gt; [您的应用名称]&gt; <类加载和更新检测> WAR类加载器策略=应用程序的单个类加载器。
必须仅在beans.xml中启用Interceptor。
答案 2 :(得分:1)
我想知道你的WAR是否缺少对你的ejb-jar的类加载器可见性?我认为理想情况下,299个拦截器将位于自己的jar中,对EJB和Web模块都可见,并在其两个beans.xml中启用。
答案 3 :(得分:0)
我在JBoss AS 6.0 / 6.1(每晚构建)上遇到了同样的问题并通过disabling separate classloaders修复了它(选项1),但要非常小心。没有任何理由没有引入类加载器的分离,所以显然前方的道路上存在新问题......
This是jira报告,请将其投票: - )
答案 4 :(得分:0)
我在JBoss 7上遇到与logging interceptor完全相同的问题,并通过将完整拦截器的jar重叠到应用程序中来修复它。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<overlays>
<overlay>
<groupId>com.github.t1</groupId>
<artifactId>logging-interceptor</artifactId>
<type>jar</type>
<targetPath>WEB-INF/classes</targetPath>
</overlay>
</overlays>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.github.t1</groupId>
<artifactId>logging-interceptor</artifactId>
<version>1.1</version>
<optional>true</optional>
</dependency>
</dependencies>
您仍然需要在应用程序的breans.xml
中激活拦截器。
不好,但确实有效。在Java EE 7中,它通过将拦截器注释为@Priority
而无需激活。
答案 5 :(得分:0)
如果您无法控制外部依赖项,并且仍然想启用没有bean.xml的拦截器,则可以编写CDI扩展名:
package my.package;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterTypeDiscovery;
import javax.enterprise.inject.spi.Extension;
public class MyCdiExtension implements Extension {
public void observeAfterTypeDiscovery(@Observes AfterTypeDiscovery afterTypeDiscovery) {
afterTypeDiscovery.getInterceptors().add(SomeExternalInterceptor.class);
}
}
添加文件resources/META-INF/services/javax.enterprise.inject.spi.Extension
内容:
my.package.MyCdiExtension