1

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

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

    private int i = 0;

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

在我的小服务程序中

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

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

然后我创建了一个耳朵,它有一个罐子和一个战争。jar 包含所有 ejb。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。

我的理解是应用服务器只创建有状态 ejb 的一个实例。我怎样才能解决这个问题?

将war中的ejb打包和单独打包在jar模块中有什么区别?

4

1 回答 1

1

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

对于不在分布式环境中托管的 servlet(默认设置),servlet 容器必须在每个 servlet 声明中仅使用一个实例。但是,对于实现 SingleThreadModel 接口的 servlet,servlet 容器可能会实例化多个实例来处理繁重的请求负载并将请求序列化到特定实例。

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

编辑

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

您应该在此处考虑的其他含义

于 2014-01-31T16:25:37.073 回答