我正在尝试使用Glassfish Server(一个简单的购物车)的第一个EJB。我打算为每个Http Session使用CartBean。如果我的购物车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 Session,我们得到一个新的有状态会话bean。这样一个用户就有一个购物车。我的理解是错误的在servlet中使用会话bean,或者下面的代码是错误的,这会为所有用户创建一个有状态会话bean。
@EJB CartLocal cart;
protected void doGet(....) throws IOException...... {
cart.addItem(....);
}
答案 0 :(得分:16)
http servlet由该servlet的所有客户端共享,因此使用有状态会话bean注入它是不正确的,并且会导致不良影响。会话bean旨在用于每个客户端,它们通常存储在http会话中,以便该会话的所有请求都可以访问会话bean。您必须在doGet
方法中使用jndi查找并将该引用存储在http会话中。存储后,您需要从http会话中检索并使用它。
更多信息
你有点不对劲。有状态会话bean类表示如何为有状态数据建模,这可能是细粒度相关类的图形。你从容器里要了一个有统计的豆子 (创建/管理/激活/钝化它)。这些服务是我们使用有状态会话bean的。然而,容器不知道它所交换的任何对象属于哪个客户端。那么http会话就会出现。这部分是不应该强调的,因为它应该是你的困惑。 Http Session是一个完美的存储位置,来自同一Web客户端的所有请求都可以访问存储在http会话中的所有属性。因此,您从容器中请求它并将其保存在某个位置(http会话),可以通过所有相同会话的请求再次引用它。现在想象一下非Web客户端的情况。在那里你没有http会话或类似的机制。您将不得不创建自己的存储机制来识别具有各自有状态bean的不同客户端。可能的方式可能是在某处存储有状态bean引用(比如在地图中将key作为clientId并将值作为bean引用),以及下次客户端想要访问bean时,它会传递clientId并从地图中获取它。
至于对有状态bean的http会话的偏好,重要的是理解http会话不是线程安全的。因此,如果你有一个ajax繁重的应用程序同时访问会话中的对象,你将不得不提供自己的同步机制 不可扩展,会严重影响性能。在有状态会话bean的情况下,容器管理同步。
Here是关于使用http会话存储状态主题的有趣讨论。讨论是关于Brian Goetz的非常有用的文章“所有有状态的Java Web应用程序都被破坏了吗?”。遗憾的是,我找不到IBM网站上的原始文章,但讨论主题提供了足够的材料来思考。
答案 1 :(得分:3)
你当然可以使用有状态bean,但是你无法注入它,因为默认情况下可以共享单个servlet实例来同时处理多个请求,这意味着你的代码不是线程安全的。但您始终可以在JNDI
方法中执行doGet
查找,例如
CartBean bean = (CartBean) new InitialContext().lookup(jndiName);
查看一些查找here的教程。