有状态会话bean在战争中打包并打包在ear-> jar中时会出现意外行为

时间:2014-01-31 08:43:50

标签: java java-ee ejb ejb-3.0 stateful-session-bean

我是ejbs的新手。我写了一个有状态的会话bean作用域@SessionScoped。然后我将ejb注入我的servlet。

@Local
@SessionScoped
@Statueful
public class CartServiceImpl implements CartService {

    private int i = 0;

    public int getI() {
        return i++;
    }
}

在我的servlet中

@Inject
private CartService cartService;
.
.
.
out.print(cartService.getI());

然后我打开了两个浏览器(IE,FF)并点击了servlet。在IE中,我看到输出从0开始到n。在firefox中我也看到输出从0开始到n。

然后我创造了一个有罐子和战争的耳朵。 jar包含所有ejbs。 war包含servlet。

这就是我将ejb注入servlet的方法

@Resource(lookup = "java:app/ejb-beginner-ejb/CartServiceImpl")
private CartService cartService; 

然后我尝试从IE和FF请求相同的servlet,我得到意外的输出。

输出如下

在IE中我第一次请求,输出为0。然后我刷新了页面,输出为1。然后我转到FF,第一次发送请求,我得到2作为输出而不是0.然后我移动到IE并刷新页面,我得到3作为输出而不是2.

我理解的是app服务器只创建有状态ejb的一个实例。我该如何解决这个问题?

在战争中包装ejbs并在jar模块中单独包装它们有什么区别?

1 个答案:

答案 0 :(得分:1)

我认为这与@SessionScoped注释仅用于Web上下文这一事实有关,否则,就像你的第二种情况一样,它没有意义,你应该假设它会被忽略,你的有状态ejb将表现得像一个旧的常规有状态ejb,一般来说,你不应该将有状态资源注入无状态资源,因为通常结果是不可预测的并且依赖于容器实现。话虽如此,servlet是无状态组件,并且规范不要求容器根据Servlet 3.0规范(2.2节)为每个请求或会话创建一个实例:

  

对于未在分布式环境中托管的servlet(缺省值),servlet   容器必须每个servlet声明只使用一个实例。但是,对于servlet   实现SingleThreadModel接口,servlet容器可以   实例化多个实例以处理繁重的请求加载和序列化请求   到一个特定的例子。

但是你甚至不应该依赖于只有一个servlet实例这一事实,因为事实上许多容器使用servlet池来提高性能,另一方面,当你查找或将有状态EJB注入无状态组件时,它是在这种情况下,你有责任照顾那个特定实例的范围,以便它可以正常工作,因为你无法控制servlet实例的实例化,也没有你的ejb实例。

修改

我会在我的Web应用程序中使用会话范围的bean,但如果你必须使用有状态的EJB(因为你需要它们提供的一些服务),那么在servlet中,在需要时查找ejb并关联它使用户HttpSession使其成为会话作用域,在这种情况下,您应该小心并确保如果会话过期,ejb通过实现会话生命周期监听器而被删除,请检查this

您应该考虑的其他含义here