Java 使用EJBContext getContextData-安全吗?
我计划使用Java 使用EJBContext getContextData-安全吗?,java,jakarta-ee,java-ee-6,ejb-3.1,Java,Jakarta Ee,Java Ee 6,Ejb 3.1,我计划使用EJBContext将一些属性从应用层(特别是消息驱动的bean)传递给无法直接注入或传递参数的持久性生命周期回调(EclipseLink中的会话侦听器、实体生命周期回调等),该回调通过JNDI获取EJBContext 这似乎是可行的,但是否有任何隐藏的陷阱,如线程安全或对象寿命,我错过了?(假设传递的属性值是不可变的,如字符串或Long。) 示例bean代码 @MessageDriven public class MDB implements MessageListener {
EJBContext
将一些属性从应用层(特别是消息驱动的bean)传递给无法直接注入或传递参数的持久性生命周期回调(EclipseLink中的会话侦听器、实体生命周期回调等),该回调通过JNDI获取EJBContext
这似乎是可行的,但是否有任何隐藏的陷阱,如线程安全或对象寿命,我错过了?(假设传递的属性值是不可变的,如字符串或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
-样结构的包装器对象吗?关于EJBContext
的问题,我无法直接帮助您,自从在JEE6中添加了getContextData
方法以来,关于它的文档仍然不多
但是,还有另一种方法可以使用在EJB、拦截器和生命周期回调之间传递上下文数据。概念和示例代码可以在本文中找到
javax.transaction.TransactionSynchronizationRegistry
持有类似于映射的结构,可用于在事务内传递状态。从旧的J2EE1.4开始,它就可以完美地工作,并且与线程无关
由于拦截器与ServiceFacade在同一事务中执行,因此甚至可以在
@AroundInvoke
方法中设置状态。TransactionSynchronizationRegistry
(TSR)可以直接注入到拦截器中
那里的示例使用
@Resource
注入来获取事务同步注册表
,但也可以从初始上下文中查找它,如下所示:
public static TransactionSynchronizationRegistry lookupTransactionSynchronizationRegistry() throws NamingException {
InitialContext ic = new InitialContext();
return (TransactionSynchronizationRegistry)ic.lookup("java:comp/TransactionSynchronizationRegistry");
}
我认为,一般来说,该方法的契约是支持拦截器+Web服务上下文和bean之间的通信。因此,只要不创建新的调用上下文,所有代码都应该可以使用上下文。因此,它应该是绝对线程安全的
EJB3.1规范的第12.6节说明了以下内容:
public Map<String, Object> getContextData() {
return CurrentInvocationContext.get().getContextData();
}
InvocationContext对象提供元数据,该元数据支持
拦截器方法来控制调用链的行为。
上下文数据不能跨单独的业务方法共享
调用或生命周期回调事件。如果调用了拦截器
作为对web服务端点调用的结果,映射
getContextData返回的将是JAX-WS MessageContext
此外,getContextData方法如4.3.3所述:
getContextData方法允许业务方法、生命周期回调方法或超时方法检索与其调用相关联的任何拦截器/webservices上下文
在实际实现方面,JBoss做了如下工作:
public Map<String, Object> getContextData() {
return CurrentInvocationContext.get().getContextData();
}
公共映射getContextData(){
返回CurrentInvocationContext.get().getContextData();
}
其中,CurrentInvocationContext
使用基于的堆栈来弹出和推送当前调用上下文
看。调用上下文只是懒洋洋地创建一个简单的HashMap
,如中所述
玻璃鱼也有类似的作用。它也会这样做,它还使用一个基于的堆栈来再次弹出和推送这些调用上下文
GlassFish实现的JavaDoc在这里特别有趣:
此TLS变量存储ArrayList。ArrayList包含
表示调用堆栈的ComponentInvocation对象
在这条线上。对ArrayList的访问不需要同步
因为每个线程都有自己的ArrayList
正如在JBoss as中一样,GlassFish也懒散地创建了一个简单的
HashMap
,在本例中为。GlassFish案例中有趣的是,webservice连接更容易在源代码中找到。好建议。我在EJBContext
中使用的模式几乎是相同的-在一个地方注入@Resource
,将对象放在地图中,然后在其他地方的JNDI中查找。因此,问题是EJBContext
对象是否也像TransactionSynchronizationRegistry
TransactionSynchronizationRegistry一样是线程独立的,它有一个限制:它总是需要一个事务,但在某些情况下需要在没有事务的情况下传播信息