Home > EJB3, SCBCD, java | > EJB3 Tutorial part 02 – Stateless vs. Stateful

EJB3 Tutorial part 02 – Stateless vs. Stateful

October 27th, 2009

In the previous post we've set up our environment to work with EJB3. It's based on Eclipse, JBoss Tools and JBoss Application Server. However you can follow the tutorial with the environment set up of your choice. Another popular one would be Netbeans. You can download it as a bundle with Glassfish server. If you decide to switch it please remember that some things presented here might be environment specific and may work differently (but most of them shouldn't).

In this post we will say a little bit more about Session Beans and we will try to cover the differences between Stateless and Stateful Session Beans.

So what are session beans? The Wikipedia will tel the truth :) A Session Bean is a component that lives inside a container (on the server). This type of component is ment to be used within a session scope. In that case a session can have a several meanings - it might be equal to a http session or just to a single http request, but it may also be equal to a longer running session of a thick client. Basically a session bean provides some operations to it's client. The stateless session bean does not maintain it's state whereas stateful session bean keeps it's state for a particular client.

In practice Session Bean is just a POJO (Plain Old Java Object) with some annotations. If you use XML deployment descriptors you can get rid of annotations also.

What's the big deal if it's just a POJO? Can't I just create a new instance using "new" keyword and use it?

Not really. Of course you can use "new" to create a new instance of a Session Bean but it won't have the same capabilities as when living inside a container. Container gives our Session Bean's some cool things:

  • it maintains it's lifecycle - it knows when to create a Session Bean and when to destroy it
  • it provides transactions - you don't have to handle transactions by yourself (but you can if you want)
  • it provides dependency injection
  • you can use your bean locally (inside the same JVM) or remotly (over the network)
  • and a few others ... :)

In the first part we've actually created a Stateless Session Bean and we've connected to it remotly from our client :) If you open the Calculator.java class you can see that it has @Stateless annotation. The CalculatorRemote interface has a @Remote annotation (it means that the Session Bean which implements this interface will be accessible remotly). Pretty cool, don't you think?

So let's add a new method to our interface:

 
package pl.mrozewski;
import javax.ejb.Remote;
 
@Remote
public interface CalculatorRemote {
  int add(int a, int b);
  int count();
}
 

And let's add the implementation:

 
package pl.mrozewski;
 
import javax.ejb.Stateless;
 
/**
* Session Bean implementation class Calculator.
*/
@Stateless
public class Calculator implements CalculatorRemote {
  private int counter = 0;
  /**
   * Default constructor.
   */
  public Calculator() {
    // TODO Auto-generated constructor stub
  }
 
  public int add(int a, int b) {
    return a + b;
  }
 
  public int count() {
    return ++counter;
  }
}
 

Our method should increment the counter and return it's value. Let's know modify our client to use the new method:

 
package pl.mrozewski;
import java.util.Properties;
 
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
import pl.mrozewski.CalculatorRemote;
 
public class Main {
public static void main(String[] args) {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
props.put(Context.PROVIDER_URL, "localhost:1099");
props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
 
try {
Context ctx = new InitialContext(props);
 
CalculatorRemote calc = (CalculatorRemote) ctx.lookup("Calculator/remote");
 
int result = calc.count();
System.out.println(result);
 
} catch (NamingException e) {
e.printStackTrace();
}
 
/* (non-Java-doc)
* @see java.lang.Object#Object()
*/
public Main() {
super();
}
}
 

If you run the client it should display the counter value. What happens if you run it again? Does the value keep growing? Probably it is. The real question is if it should :) A few lines above I said that Stateless Session Beans do not keep their state and here we can see that they do! Please note that this may not happen to you :) I'm about to explain why.

Most application servers will use instance pooling - instead of creating the objects every time a call is made, they keep a certain amount of already created objects and just reuse them. It's because it may be very expensive to create a new ready to work object. In our example it's just an object but real world Session Beans will have some resources like database connections and others and creating all of these might be very expensive. Thus the reuse of instances makes a lot of sense. However you have to remember that the counter example is just a side effect. It is not deterministic - the value may keep growing (you always get the same instance) and suddenly you may get a completely new instance (container decides when). You should always assume that you call a fresh, new instance with no state and memory. You can try to loop the code in out client and try to run a few clients at the same time - you should get more random values.

Lets now move to Stateful Session Beans. Let's modify our Session Bean to become a Stateful one:

 
package pl.mrozewski;
 
import javax.ejb.Stateful;
 
/**
* Session Bean implementation class Calculator.
*/
@Stateful
public class Calculator implements CalculatorRemote {
private int counter = 0;
/**
* Default constructor.
*/
public Calculator() {
// TODO Auto-generated constructor stub
}
 
public int add(int a, int b) {
return a + b;
}
 
public int count() {
return ++counter;
}
}
 

As you can see the only thing that changed is the annotation. If restart the server and run the client now you should always get 1 as a result of the count method. Now put the call to count() method and the print statement inside a loop with a counter from 0 to 10 and run the client. What are the results know? They grow from 1 to 10 - the Stateful Session Bean keeps it's state for a single client. The JSR-220 specification says that for every JNDI lookup container must provide a new instance of a Stateful Session Bean. Imagine if that wouldn't happen - would you like to get someone else shopping cart to pay for? (Shopping cart is probably the most common example of a Stateful Session Bean).

Summary and further reading

In this post we've learned the basic differences between Stateless and Stateful Session Beans. Of course there is much more to the subject but this is just for starters. If you would like to get more details you can read:

As a practice try to think of a usage for a Stateless and Stateful Session Beans. Calculator and shopping cart are two examples from this post. What others can you think of?

In next post we will cover more details on Session Beans' lifecycle.

EJB3, SCBCD, java |

  1. No comments yet.
  1. No trackbacks yet.