有状态的会话bean在包装在战争中并打包在ear-> jar中时出现意外行为 [英] Stateful session beans unexpected behaviour when packaged in a war and packaged in an ear->jar

查看:144
本文介绍了有状态的会话bean在包装在战争中并打包在ear-> jar中时出现意外行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  @Local 
@SessionScoped
@Statueful
public class CartServiceImpl实现CartService {

private int i = 0;

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

在我的servlet中

  @Inject 
私人CartService cartService;



out.print(cartService.getI());

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



然后我创建了一个有一个罐子和一个战争的耳朵。该jar包含所有ejbs。战争包含servlets。



这是我如何将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的一个实例。如何解决这个问题?



打包战争中的ejbs有什么区别,并在jar模块中单独打包?

解决方案

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



对于未在分布式环境中托管的servlet(默认值),servlet
容器必须在每个servlet声明中只使用一个实例。然而,对于实现SingleThreadModel接口的servlet
,servlet容器可以
实例化多个实例来处理繁重的请求加载并将请求
序列化到特定实例。但是你不应该依赖这个事实,只有一个servlet实例,因为实际上很多容器都使用servlet池来提高性能。另一方面,当您将有状态的EJB查找或注入无状态组件时,您有责任处理该特定实例的范围,以便在这种情况下可以正常工作,因为您不要您可以控制您的servlet实例的实例化,您也不必在ejb实例上实现。



编辑



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



您应该考虑的其他影响这里


I am new to ejbs. I wrote a stateful session bean scoped @SessionScoped. Then I injected the ejb into my servlet.

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

    private int i = 0;

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

In my servlet

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

Then I opened two browsers (IE, FF) and have hit the servlet. In IE I see output starting from 0 to n. In firefox also I see the output starting from 0 to n.

Then I created created an ear which has a jar and a war. The jar contains all ejbs. war contains the servlets.

This is how I injected the ejb into the servlet

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

Then I tried requesting the same servlet from IE and FF and I get unexpected output.

The output is as follows

In IE I requested for first time and I get 0 as output. Then I refreshed the page and I get 1 as output. Then I move to FF, send the request for first time and I get 2 as output instead of 0. Then I move to IE and refresh the page and I get 3 as output instead of 2.

What I understood is the app server is creating only one instance of the stateful ejb. How can I fix this?

What is the difference between packaging the ejbs in the war and packaging them separately in a jar module?

解决方案

I think it has to do with the fact that the @SessionScoped annotation is meant to be used only in a web context, otherwise, like in your your second case, it doesn't make sense and you should assume that it will be ignored and your stateful ejb will behave like an old regular stateful ejb, and in general, you shouldn't inject stateful resources into stateless ones because usually the results are unpredictable and dependent on the container implementation. Having said that, servlets are stateless components, and the container is not required by the spec to create one instance per request or session, from the Servlet 3.0 spec (Sec. 2.2):

For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration. However, for a servlet implementing the SingleThreadModel interface, the servlet container may instantiate multiple instances to handle a heavy request load and serialize requests to a particular instance.

however you shouldn't even rely on the fact that there's only one servlet instance since in fact many containers use servlet pooling to increase performance, on the other hand, when you look up or inject a stateful EJB into a stateless component it's your responsibility to take care of the scope of that particular instance so that it can work as it's supposed to, in this case, since you don't have control over the instantiation of your servlet instances, neither you have it over your ejb instances.

EDIT

I would use session scoped beans in my web app, but if you definitely have to use stateful EJBs (because you need some of the services provided by them) than you could, in the servlet, lookup the ejb when needed and associate it to the user HttpSession to make it session scoped, in this case, you should be careful and make sure that if the session expires the ejb gets removed by implementing session lifecycle listeners, check this

other implications you should consider here

这篇关于有状态的会话bean在包装在战争中并打包在ear-> jar中时出现意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆