我的开发环境是: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/