我的开发环境是:WildFly 8.1,CDI,EJB 3.2,JDK 1.7。应用程序被打包为一个耳朵存档(一个ejb +一个战争),因为它可能会在未来拥有其他网络模块。
我正在努力使用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());
}
}
// .....
}
然后注入开始工作,但我收到了一个新错误:
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 {
}
然后它开始工作。但为什么呢? 为什么我不能在方法上加注我的注释?有人知道吗?
BTW:当我没有使用@InterceptorBinding
时,更奇怪的是,但是很平常:
@Override
// @DetectIntegrityConstraintsViolation
@Interceptors(ReferentialIntegrityConstraintViolationInterceptor.class)
public User updateUser(final User user) {
// ...
}
拦截器即使在方法级别上也能完美运行。
我发现EJB和Weld使用起来很笨拙......
答案 0 :(得分:4)
生命周期回调的拦截器可能只声明拦截器 绑定类型,定义为@Target(TYPE)。如果是一个拦截器 生命周期回调声明了一个拦截器绑定类型 定义@Target({TYPE,METHOD}),容器自动检测 问题并将其视为定义错误。
您已使用@PostConstruct init(InvocationContext ctx)
创建了生命周期回调。这个回调是为了在你正在拦截的bean的构造上运行,所以将它应用于一个方法是没有意义的。
至于为什么普通的@Interceptor
工作正常,documentation中也有描述:
可以将around-invoke拦截器定义为仅应用于a 目标类的具体方法。同样,周围超时 可以将拦截器定义为仅应用于特定的超时方法 目标类。但是,如果一个拦截器类定义 生命周期回调拦截器方法被定义为应用于目标 类在方法级别,生命周期回调拦截器方法 没有被援引。
至于此:
我发现EJB和Weld使用起来很笨拙......
如果你放慢脚步并尝试学习,你会有更轻松的时间。您似乎正在尝试随机的事情,并对结果感到困惑,如果您不熟悉CDI和EJB,这是可以预期的。
我还担心你正在使用@ManagedBean
注释。一个,它实际上是deprecated,两个,它是JSF,你没有说你正在使用它。
答案 1 :(得分:1)
感谢@DavidS,我设法让它发挥作用。感谢他。
他指出,@Interceptor里面的@PostConstruct
与我想的意思不同。
下面带有注释的正确代码:
@Inherited
@InterceptorBinding
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
@Documented
public @interface DetectIntegrityConstraintsViolation {
}
import javax.annotation.ManagedBean;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.persistence.PersistenceContext;
@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(name = "java:comp/EJBContext") // injecting Java EE resource into CDI bean
private SessionContext sessionContext;
@AroundInvoke
public Object processInvocation(InvocationContext ctx) throws Exception {
// ...
}
}
所以现在我可以在我的EJB bean中使用:
@DetectIntegrityConstraintsViolation
public User updateUser(final User user) {
// ...
}
而不是:
@Interceptors(ReferentialIntegrityConstraintViolationInterceptor.class)
public User updateUser(final User user) {
// ...
}
未来来到这里的人们的解释:
@InterceptorBinding
机制来自CDI世界,因此拦截器本身必须成为CDI bean。它带来了一些后果:
beans.xml
bean-discovery-mode="annotated"
)必须成为CDI bean;所以用@javax.interceptor.Interceptor
注释它。不幸的是,WildFly 8.1似乎有一些bug,因为它没有@javax.annotation.ManagedBean
拒绝工作。