10

我正在尝试我的第一个 EJB 与 Glassfish 服务器(一个简单的购物车)。我打算为每个 Http 会话使用 CartBean。如果我的 Cart Bean 正在关注 -

public interface CartLocal {
 public void addItem(String item);
 public void removeItem(String item);
}

@Stateful
public class CartBean implements CartLocal {
 List<String> item = new java.util.ArrayList<String>();
 public void addItem(String item) {
  ....
 }
 public void removeItem(String item) {
  ....
 }
}

我必须在 web servlet 客户端中使用上述有状态会话 bean,这样对于每个新的 Http 会话,我们都会获得一个新的有状态会话 bean。这样一个用户就有一个购物车。我对在 servlet 中使用会话 bean 的理解是错误的还是下面的代码是错误的,这会为所有用户创建一个有状态会话 bean。

@EJB CartLocal cart;

protected void doGet(....) throws IOException...... {
 cart.addItem(....);
}
4

2 回答 2

18

http servlet 由该 servlet 的所有客户端共享,因此使用有状态会话 bean 注入它是不正确的,并且会导致不良影响。会话 bean 旨在为每个客户端使用,它们通常存储在 http 会话中,以便该会话的所有请求都可以访问会话 bean。您必须在doGet方法中使用 jndi 查找并将该引用存储在 http 会话中。存储后,您需要从 http 会话中检索并使用它。

更多信息

你搞错了。有状态会话 bean 类表示您如何对有状态数据建模,这可能是细粒度相关类的图。您从容器中请求一个 statful bean(它创建/管理/激活/钝化它)。这些服务是我们使用 Stateful session bean 的目的。但是容器不知道它所移交的任何对象属于哪个客户端。那么http会话就出现了。这部分没有得到应有的强调,因此您感到困惑。Http Session 是一个完美的存储位置,来自同一个 Web 客户端的所有请求都可以访问存储在 http 会话中的所有属性。因此,您从容器中请求它并将其保存在一个位置(http 会话)中,从该位置它可以被同一会话的所有请求再次引用。现在想象一下非 Web 客户端的情况。那里没有 http 会话或类似的机制。您将必须创建自己的存储机制,以使用各自的有状态 bean 来识别不同的客户端。一种可能的方法可能是将有状态 bean 引用存储在某处(例如在映射中,键作为 clientId,值作为 bean 引用),并且下次客户端想要访问 bean 时,它会传递 clientId 并从映射中获取它。

就 http 会话优于有状态 bean 而言,重要的是要了解 http 会话不是线程安全的。因此,如果您有一个 ajax 繁重的应用程序同时访问会话中的对象,您将不得不提供自己的同步机制,该机制不可扩展并且会严重影响性能。在有状态会话 bean 的情况下,容器管理同步。

是关于使用 http 会话存储状态的主题的有趣讨论。讨论是在 Brian Goetz 的内容丰富的文章“Are All Stateful Java Web Applications Broken?”中进行的。不幸的是,我在 IBM 站点上找不到原始文章,但讨论线程提供了足够的材料来思考。

于 2013-11-13T06:42:00.423 回答
4

您当然可以使用有状态 bean,但您不能注入它,因为默认情况下可以共享单个 servlet 实例以同时服务多个请求,这意味着您的代码不是线程安全的。但是您总是可以JNDI在您的方法中执行查找,doGet例如

CartBean bean = (CartBean) new InitialContext().lookup(jndiName);

请参阅此处进行查找的一些教程。

于 2013-11-13T09:58:06.093 回答