java - @InterceptorBinding/CDI/EJB 3.2 - 注入(inject)问题

标签 java jakarta-ee cdi wildfly-8 java-ee-7

我的开发环境是:WildFly 8.1、CDI、EJB 3.2、JDK 1.7。应用程序打包为 ear archive(一个 ejb + 一个 war),因为将来它可能会有其他 web 模块。

我正在努力处理在我的 EJB 无状态 bean 中使用的自定义 @InterceptorBinding 类型。

@Inherited
@InterceptorBinding
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
@Documented
public @interface DetectIntegrityConstraintsViolation {
}

@javax.annotation.ManagedBean  // make it a CDI bean. @Interceptor itself should be enough, but WildFly 8.1 seems to have a bug, since it doesn't work without this line.
@Interceptor
@DetectIntegrityConstraintsViolation
public class ReferentialIntegrityConstraintViolationInterceptor {

    @PersistenceContext
    private EntityManager em;

    @Resource
    private SessionContext sessionContext;

    // ....
 }

beans.xml:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="annotated">

  <interceptors>
    <class>com.xxx.ejb.ReferentialIntegrityConstraintViolationInterceptor</class>
  </interceptors>
</beans>

当我通过 REST 服务调用我的 EJB 方法时,我得到了Error injecting resource into CDI managed bean:

javax.naming.NameNotFoundException: Caused by java.lang.IllegalStateException: JBAS011048: Failed to construct component instance  Caused by: java.lang.IllegalArgumentException: JBAS016081: Error injecting resource into CDI managed bean.
Can't find a resource named java:comp/env/com.xxx.ejb.ReferentialIntegrityConstraintViolationInterceptor/sessionContext defined on private javax.ejb.SessionContext com.xxx.ejb.ReferentialIntegrityConstraintViolationInterceptor.sessionContext   at org.jboss.as.weld.services.bootstrap.WeldResourceInjectionServices.resolveResource(WeldResourceInjectionServices.java:188) [wildfly-weld-8.1.0.Final.jar:8.1.0.Final]

所以在黑暗中行走,我转向了 ResourceLookup 方法:

@ManagedBean
@Interceptor
@DetectIntegrityConstraintsViolation
public class ReferentialIntegrityConstraintViolationInterceptor {

    @PersistenceContext
    private EntityManager em;

    private SessionContext sessionContext;

    @PostConstruct
    public void init(InvocationContext ctx) {
        try {
            InitialContext ic = new InitialContext();
            this.sessionContext = (SessionContext)ic.lookup("java:comp/EJBContext");
        } catch (NamingException ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }

    // .....
}

然后注入(inject)开始工作,但是我得到了一个新的错误:

Caused by: org.jboss.weld.exceptions.DefinitionException: WELD-000619: An interceptor for lifecycle callbacks Interceptor [class com.xxx.ejb.ReferentialIntegrityConstraintViolationInterceptor intercepts @DetectIntegrityConstraintsViolation] declares and interceptor binding interface com.xxx.ejb.DetectIntegrityConstraintsViolation with METHOD as its @Target.

因此,当从 DetectIntegrityConstraintsViolation 中删除一个 METHOD 目标时:

@Inherited
@InterceptorBinding
@Target({ TYPE /*, METHOD*/ }) // CRUCIAL
@Retention(RUNTIME)
@Documented
public @interface DetectIntegrityConstraintsViolation {
}

然后它开始工作。但是为什么??
为什么我不能在方法上放置注释?有人知道吗?

顺便说一句:更奇怪的是,当我没有使用@InterceptorBinding,而是使用普通的旧代码时:

@Override
// @DetectIntegrityConstraintsViolation
@Interceptors(ReferentialIntegrityConstraintViolationInterceptor.class)
public User updateUser(final User user) {
    // ...
}

拦截器即使在方法级别也能完美运行。

我发现 EJB 和 Weld 很难用...

最佳答案

CDI spec 中描述了您的一条错误消息:

An interceptor for lifecycle callbacks may only declare interceptor binding types that are defined as @Target(TYPE). If an interceptor for lifecycle callbacks declares an interceptor binding type that is defined @Target({TYPE, METHOD}), the container automatically detects the problem and treats it as a definition error.

您已经使用 @PostConstruct init(InvocationContext ctx) 创建了一个生命周期回调。此回调旨在在您拦截的 bean 的构造上运行,因此将其应用于方法没有意义。

至于为什么普通的旧 @Interceptor 可以工作,这也在 documentation 中有所描述。 :

An around-invoke interceptor may be defined to apply only to a specific method of the target class. Likewise, an around-timeout interceptor may be defined to apply only to a specific timeout method of the target class. However, if an interceptor class that defines lifecycle callback interceptor methods is defined to apply to a target class at the method level, the lifecycle callback interceptor methods are not invoked.

至于这个:

I find EJB and Weld so awkward to use...

如果你放慢脚步并边学边学,你会过得更轻松。您似乎在尝试随机的事情并且对结果感到困惑,如果您不熟悉 CDI 和 EJB,这是可以预料的。

我还担心您正在使用 @ManagedBean 注释。第一,实际上是 deprecated ,第二,它用于 JSF,您没有说您正在使用它。

关于java - @InterceptorBinding/CDI/EJB 3.2 - 注入(inject)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30894880/

相关文章:

java - CDI 会(或应该)提供包限定符吗?

java - 使用 hibernate 进行多个子插入的父表

Java SecurityManager 防止 .. 目录使用

Java:简单 JAR 项目在运行时无法在第二个简单 JAR 项目中找到导入的类,即使第二个 JAR 通过 -classpath 传递

java - EventQueue 和 EventDispatch 错误

web-services - JAX-WS Web 服务,使用 HTTPS 端点 URL 而不是 HTTP 的负载平衡器

java - 如何为 Web 服务实例分配唯一 ID

java - Liberty 配置文件未在 servlet 中注入(inject) ejb

java - 尝试在 Tomcat 7 中使用 Jersey (JAX-RS) 和 Weld (CDI)。为 javax.annotation.ManagedBean 获取 noClassDefFoundError

java - session 不会在表单提交时自动传播?