Stateful session beans unexpected behaviour when p

2019-07-23 08:11发布

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?

1条回答
仙女界的扛把子
2楼-- · 2019-07-23 08:40

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

查看更多
登录 后发表回答