Stateless and Stateful Enterprise Java Beans
Asked Answered
E

7

99

I am going through the Java EE 6 tutorial and I am trying to understand the difference between stateless and stateful session beans. If stateless session beans do not retain their state in between method calls, why is my program acting the way it is?

package mybeans;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

@LocalBean
@Stateless
public class MyBean {

    private int number = 0;

    public int getNumber() {
        return number;
    }

    public void increment() {
        this.number++;
    }
}

The client

import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import mybeans.MyBean;
import java.io.PrintWriter;

@WebServlet(name = "ServletClient", urlPatterns = { "/ServletClient" })
public class ServletClient extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @EJB
    MyBean mybean;

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {

        PrintWriter out = response.getWriter();
        mybean.increment();
        out.println(mybean.getNumber());
    }

}

I was expecting getNumber to return 0 every time but it is returning 1 and reloads of the servlet in my browser increase it more. The problem is with my understanding of how stateless session beans work and not with the libraries or application server, of course. Can somebody give me a simple hello world type example of a stateless session bean that behaves differently when you change it to stateful?

Extensive answered 28/2, 2010 at 13:52 Comment(3)
Related: #8887640 This answer is maybe simpler to understand. Note that servlets are basically application scoped (there's only 1 servlet instance applicationwide which is shared/reused across all HTTP requests/sessions.Rom
hi, You do first increment, and then get the value .... so You cannot expect value of 0.Driedup
I just wanna thank you for asking this, it addresses my problem at the moment. I could not have asked that betterCarley
S
97

The important difference is not private member variables, but associating state with a particular user (think "shopping cart").

The stateful piece of stateful session bean is like the session in servlets. Stateful session beans allow your app to still have that session even if there isn't a web client. When the app server fetches a stateless session bean out of the object pool, it knows that it can be used to satisfy ANY request, because it's not associated with a particular user.

A stateful session bean has to be doled out to the user that got it in the first place, because their shopping cart info should be known only to them. The app server ensures that this is so. Imagine how popular your app would be if you could start shopping and then the app server gave your stateful session bean to me when I came along!

So your private data member is indeed "state", but it's not "shopping cart". Try to redo your (very good) example to make it so the incremented variable is associated with a particular user. Increment it, create a new user, and see if they can still see the incremented value. If done correctly, every user should see just their version of the counter.

Saturant answered 28/2, 2010 at 13:57 Comment(2)
Can you provide in a comment an explicit answer? Why does always the stateless bean in this example hold the value and increase it every time? Because there is only one user?Persimmon
The counter will increment irrespective of the number of users. So if user1 comes in and increments the counter to 1 and simultaneously user2 comes in and increments it, the value will be 2. It actually should show that user1 has 1 and user2 has 1 ( if thats what you are intending to do. Shopping cart example as above).Courtesan
A
138

Stateless Session Beans (SLSB) are not tied to one client and there is no guarantee for one client to get the same instance with each method invocation (some containers may create and destroy beans with each method invocation session, this is an implementation-specific decision, but instances are typically pooled - and I don't mention clustered environments). In other words, although stateless beans may have instance variables, these fields are not specific to one client, so don't rely on them between remote calls.

In contrast, Stateful Session Beans (SFSB) are dedicated to one client for their entire life, there is no swapping or pooling of instances (it may be evicted from memory after passivation to save resources but that's another story) and maintain conversational state. This means that the instance variables of the bean can keep data relative to the client between method invocations. And this makes possible to have interdependent method calls (changes made by one method affect subsequent method calls). Multi-step processes (a registration process, a shopping cart, a booking process...) are typical use cases for SFSB.

One more thing. If you are using SFSB, then you must avoid injecting them into classes that are multithreaded in nature, such as Servlets and JSF managed beans (you don't want it to be shared by all clients). If you want to use SFSB in your web application, then you need to perform a JNDI lookup and store the returned EJB instance in the HttpSession object for future activity. Something like that:

try {
    InitialContext ctx = new InitialContext();
    myStateful = (MyStateful)ctx.lookup("java:comp/env/MyStatefulBean");
    session.setAttribute("my_stateful", myStateful);
} catch (Exception e) {
    // exception handling
}
Avelin answered 28/2, 2010 at 15:21 Comment(6)
Thanks for the clear up. When I use a standalone command line program for the client, it is obvious to see the difference.Extensive
thanks for you comments, they are more enlightening. first your give the abstract definition, then specify some use cases for each situation, and then point out some pitfalls. Great +1Homeric
Does the avoid injecting part goes out for EJB 3.1 as well?Coom
@Pascal if "Stateful Session Beans (SFSB) are dedicated to one client for their entire life", that is this ability is built in SFSB, then why need to store them on HttpSession object?Frisian
Why we need hold stateful bean in session if it already 'sessioned'? This way we can make every object sessioned. Explain plsAddiction
This is the most irritating thing about J2EE: I want to use Stateful ejbs and just do the injection in my servlet for example. I expect the framework to perform some "threadLocal" work - as ejb link is proxied anyway - just to return the real session bean for my http session, but not any one! So, Georgy is completely right - why do we need SFSB if we can create the simple bean, put it into http session and use it everywhere??? Only to get JPA and other staff that is allowed for EJB?Winch
S
97

The important difference is not private member variables, but associating state with a particular user (think "shopping cart").

The stateful piece of stateful session bean is like the session in servlets. Stateful session beans allow your app to still have that session even if there isn't a web client. When the app server fetches a stateless session bean out of the object pool, it knows that it can be used to satisfy ANY request, because it's not associated with a particular user.

A stateful session bean has to be doled out to the user that got it in the first place, because their shopping cart info should be known only to them. The app server ensures that this is so. Imagine how popular your app would be if you could start shopping and then the app server gave your stateful session bean to me when I came along!

So your private data member is indeed "state", but it's not "shopping cart". Try to redo your (very good) example to make it so the incremented variable is associated with a particular user. Increment it, create a new user, and see if they can still see the incremented value. If done correctly, every user should see just their version of the counter.

Saturant answered 28/2, 2010 at 13:57 Comment(2)
Can you provide in a comment an explicit answer? Why does always the stateless bean in this example hold the value and increase it every time? Because there is only one user?Persimmon
The counter will increment irrespective of the number of users. So if user1 comes in and increments the counter to 1 and simultaneously user2 comes in and increments it, the value will be 2. It actually should show that user1 has 1 and user2 has 1 ( if thats what you are intending to do. Shopping cart example as above).Courtesan
T
19

Stateless and stateful in this context don't mean quite what you might expect.

Statefulness with EJBs refers to what I call conversational state. The classic example is a flight booking. If it consists of three steps:

  • Reserve seat
  • Charge credit card
  • Issue Ticket

Imagine each of those is a method call to a session bean. A stateful session bean can maintain this kind of conversation so it remembers what happens between calls.

Stateless session beans don't have such capacity for conversational state.

Global variables inside a session bean (stateless or stateful) are something else entirely. Stateful session beans will have a pool of beans created (since a bean can only be used in one conversation at a time) whereas stateless sesion beans will often only have one instance, which will make the global variable works, but I don't think this is necessarily guaranteed.

Trigg answered 28/2, 2010 at 13:59 Comment(0)
W
7

Good Question,

try this code (change MyBean Stateful/Stateless.):

import javax.ejb.LocalBean;
import javax.ejb.Stateful;
import javax.ejb.Stateless;

@LocalBean 
@Stateless 
public class MyBean {

    private int number = 0;

    public int getNumber() {
        return number;
    }

    public void increment() {
        this.number++;
    }
}

Servlet_1

 import java.io.IOException;
    import javax.ejb.EJB;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import javax.servlet.annotation.WebServlet;

    import java.io.PrintWriter;

    @WebServlet(name = "ServletClient", urlPatterns = { "/ServletClient" })
    public class ServletClient extends HttpServlet {

        private static final long serialVersionUID = 1L;

        @EJB
        MyBean mybean;

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

            PrintWriter out = response.getWriter();
            mybean.increment();
            out.println(mybean.getNumber());
        }

    }

Servlet_2

import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;

import java.io.PrintWriter;

@WebServlet(name = "NewServletClient", urlPatterns = { "/NewServletClient" })
public class NewServletClient extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @EJB
    MyBean mybean;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        PrintWriter out = response.getWriter();
        mybean.increment();
        out.println(mybean.getNumber());
    }

}

case : MyBean -@Stateless

http://localhost:8080/MYServletDemo/ServletClient

1

http://localhost:8080/MYServletDemo/ServletClient

2

http://localhost:8080/MYServletDemo_war_exploded/newServletClient

3

http://localhost:8080/MYServletDemo/ServletClient

4

case : MyBean -@Stateful

http://localhost:8080/MYServletDemo/ServletClient

1

http://localhost:8080/MYServletDemo/ServletClient

2

http://localhost:8080/MYServletDemo/newServletClient

1

http://localhost:8080/MYServletDemo/ServletClient

3

Wolfsbane answered 23/10, 2018 at 8:22 Comment(1)
Yes, that's It and It works! Very easy explanation, thanks!Originality
M
5

The major differences between the two major types of session beans are:

Stateless Beans

  1. Stateless Session Beans are the ones which have no conversational state with the client which has called its methods. For this reason they can create a pool of objects which can be used to interact with multiple clients.
  2. Performance wise stateless beans are better since they don't have states per client.
  3. They can handle multiple requests from multiple clients in parallel.

Stateful Beans

  1. Stateful session beans can maintain the conversational state with multiple clients at a time and the task is not shared between the clients.
  2. After the session is completed the state is not retained.
  3. The container can serialize and store the state as a stale state for future use. This is done to save resources of the application server and to support bean failures.
Microcopy answered 20/2, 2017 at 20:8 Comment(0)
M
4

This thing happen because the container only has one bean instance in the pool that is being reused for all calls. If you run the clients in parallel you will see a different result because the container will create more bean instances in the pool.

Mayence answered 28/5, 2013 at 22:25 Comment(0)
T
4

It has good answers. I would like to add small answer. Stateless Bean should not used to hold any client data. It should be used to "to model actions or processes that can be done in one shot".

Triggerfish answered 27/3, 2016 at 5:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.