18

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

<beans>
    <interceptors>
        <class>com.test.interceptor.LoggingInterceptor</class>
    </interceptors>
</beans>

这仅适用于在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)});
        }
    }

}

和拦截器绑定:

@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Log {}

如何将拦截器用于两个模块?

4

6 回答 6

12

J2EE 7 specification says (reference):

The interceptors that you specify in the beans.xml file apply only to classes in the same archive. Use the @Priority annotation to specify interceptors globally for an application that consists of multiple modules

This solution has the advantage of being vendor independent.

An Example:

@Logged
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class LoggedInterceptor implements Serializable { ... }
于 2013-07-10T12:42:08.870 回答
5

It is too late, but if somebody still having this problem. Both modules should be loaded by the same classloader to make usage of interceptor across different modules possible, at least in WebSphere 8b2. In WebSphere this setting can be switched in administration console: Applications > Application Types > WebSphere enterprise applications > [your app name] > Class loading and update detection > WAR class loader policy = Single class loader for application.
Interceptor must be enabled only ONCE in beans.xml.

于 2011-04-18T15:10:28.790 回答
1

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

于 2011-01-08T14:22:22.590 回答
0

我在 JBoss 7 上的日志拦截器遇到了完全相同的问题,并通过将完整的拦截器的 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.

于 2014-04-27T21:05:36.623 回答
0

我在 JBoss AS 6.0 / 6.1(夜间构建)上遇到了同样的问题,并通过禁用单独的类加载器(选项 1)来修复它,但要非常小心。类加载器的分离还没有无缘无故的引入,那么显然前面的路上又出现了新的问题……

是 jira 报告,请投票 :-)

于 2011-04-20T11:29:02.500 回答
0

如果您无法控制外部依赖项,并且仍希望在没有 beans.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
于 2019-10-03T15:29:25.873 回答