我打算使用EJBContext将一些属性从应用程序层(特别是消息驱动的Bean)传递到无法直接注入(inject)或传递参数的持久性生命周期回调(EclipseLink中的 session 监听器,实体生命周期回调等)。 ,并且该回调函数通过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的结构的包装对象?

最佳答案

我认为一般而言,该方法的约定是启用拦截器+ Web服务上下文与Bean之间的通信。因此,只要没有创建新的调用上下文,该上下文应可用于所有代码。因此,它应该绝对是线程安全的。

EJB 3.1规范的第12.6节指出:



此外,在4.3.3中描述了getContextData方法:



在实际实现方面,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在这里特别有趣:



就像在JBoss AS中一样,GlassFish也懒惰地创建了一个简单的HashMap,在本例中是com.sun.ejb.EjbInvocation。在GlassFish案例中,有趣的是Web服务连接更容易在源中发现。

10-06 01:47