这似乎是有效的,但是有没有隐藏的问题,如线程安全或对象生命周期,我失踪了? (假设传递的属性值是不可变的,如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映射内容只对当前的调用/线程可见吗?换句话说,如果两个线程同时运行回调方法,并且都从JNDI中查找一个EJBContext,它们实际上会得到不同的contextData映射内容?
而且,这是如何实际工作的 – EJBontext从JNDI查找返回真的是一个围绕ThreadLocal的结构的包装对象?
解决方法
EJB 3.1规范的第12.6节说:
The InvocationContext object provides Metadata that enables
interceptor methods to control the behavior of the invocation chain.
The contextual data is not sharable across separate business method
invocations or lifecycle callback events. If interceptors are invoked
as a result of the invocation on a web service endpoint,the map
returned by getContextData will be the JAX-WS MessageContext
此外,getContextData方法在4.3.3中描述:
The getContextData method enables a business method,lifecycle callback method,or timeout method to retrieve any interceptor/webservices context associated with its invocation.
在实际实现方面,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在这里非常有趣:
This TLS variable stores an ArrayList. The ArrayList contains
ComponentInvocation objects which represent the stack of invocations
on this thread. Accesses to the ArrayList dont need to be synchronized
because each thread has its own ArrayList.
就像JBoss AS一样,GlassFish也懒洋洋地创建了一个简单的HashMap,在这种情况下在com.sun.ejb.EjbInvocation.对GlassFish的情况感兴趣的是,Webservice连接更容易在源中发现.