我打算使用EJBContext
将一些属性从应用程序层(特别是消息驱动的bean)传递给不能直接注入或传递参数的持久性生命周期回调(EclipseLink中的会话侦听器,实体生命周期回调等),并且该回调通过JNDI获取EJBContext
。
这似乎有用,但是有没有任何隐藏的陷阱,比如我缺少的线程安全或对象生命周期? (假设传递的属性值是不可变的,如String或Long。)
示例bean代码
@MessageDriven
public class MDB implements MessageListener {
private @Resource MessageDrivenContext context;
public void onMessage(Message m) {
context.getContextData().put("property", "value");
}
}
然后是使用EJBContext的回调
public void callback() {
InitialContext ic = new InitialContext();
EJBContext context = (EJBContext) ic.lookup("java:comp/EJBContext");
String value = (String) context.getContextData().get("property");
}
我想知道的是,我能确定contextData
地图内容只对当前的调用/线程可见吗?换句话说,如果两个线程同时运行callback
方法,并且都从JNDI查找EJBContext
,那么它们实际上会获得不同的contextData
映射内容?
而且,这实际上是如何工作的 - 从JNDI查找返回的EJBContext
真的是一个围绕ThreadLocal
类似结构的包装器对象吗?
答案 0 :(得分:10)
我认为通常方法的合同是启用拦截器+ webservice上下文和bean之间的通信。因此,只要没有创建新的调用上下文,所有代码都可以使用上下文。因此,它应该绝对是线程安全的。
EJB 3.1规范的第12.6节说明如下:
InvocationContext对象提供启用的元数据 拦截器方法来控制调用链的行为。 上下文数据不能在单独的业务方法中共享 调用或生命周期回调事件。如果调用拦截器 作为在Web服务端点上调用映射的结果 getContextData返回的将是JAX-WS MessageContext
此外,getContextData方法在4.3.3中描述:
getContextData方法使业务方法,生命周期回调方法或超时方法能够检索与其调用关联的任何拦截器/ webservices上下文。
在实际实现方面,JBoss AS执行以下操作:
public Map<String, Object> getContextData() {
return CurrentInvocationContext.get().getContextData();
}
CurrentInvocationContext
使用基于thread-local linked list的堆栈来弹出并推送当前的调用上下文。
见org.jboss.ejb3.context.CurrentInvocationContext。调用上下文只是懒惰地创建了一个简单的HashMap
,就像org.jboss.ejb3.interceptor.InvocationContextImpl中所做的那样
Glassfish做了类似的事情。它也是gets an invocation,并执行此from an invocation manager,它还使用基于thread-local array list的堆栈来再次弹出和推送这些调用上下文。
GlassFish实现的JavaDoc在这里特别有趣:
此TLS变量存储ArrayList。 ArrayList包含 ComponentInvocation对象,表示调用堆栈 在这个线程上。对ArrayList的访问不需要同步 因为每个线程都有自己的ArrayList。
就像在JBoss AS中一样,GlassFish也懒得创建一个简单的HashMap
,在本例中是com.sun.ejb.EjbInvocation。对GlassFish案例感兴趣的是,Web服务连接更容易在源中发现。
答案 1 :(得分:8)
我无法直接帮助您解决有关EJBContext
的问题,因为在JEE6中添加了getContextData
方法,但仍然没有太多关于它的文档。
然而,有另一种方法可以使用TransactionSynchronizationRegistry在EJB,拦截器和生命周期回调之间传递上下文数据。可以在此blog post by Adam Bien中找到概念和示例代码。
javax.transaction.TransactionSynchronizationRegistry
包含类似Map的结构,可用于在事务内传递状态。它从旧的J2EE 1.4天开始就完美运行,并且与线程无关。因为Interceptor在与ServiceFacade相同的事务中执行,所以甚至可以在
@AroundInvoke
方法中设置状态。TransactionSynchronizationRegistry
(TSR)可以直接注入拦截器。
此示例使用@Resource
注入来获取TransactionSynchronizationRegistry
,但也可以从InitialContext
中查找,如下所示:
public static TransactionSynchronizationRegistry lookupTransactionSynchronizationRegistry() throws NamingException {
InitialContext ic = new InitialContext();
return (TransactionSynchronizationRegistry)ic.lookup("java:comp/TransactionSynchronizationRegistry");
}