Defrosting Stateless Session Beans with MBean Singletons September 3rd, 2003

Stateless session beans are often used as facades for complex or expensive operations in J2EE applications. They're relatively lightweight and benefit from pooling.

One of the problems you can run into with these babies is that facades that perform expensive operations at the beginning of their lifecycle may be very slow for the unlucky consumers whose requests give birth to them. The problem is that the J2EE specification doesn't offer you much in the way of standard ways to control the lifecycle of stateless session beans. This is a good thing, because it keeps their implementation and deployment simple. Of all the components of the EJB specification, stateless session beans are the ones that the smallest number of developers take exception to.

So then how do you get them to perform these expensive startup operations at deployment time? You don't. You can't. Not portably, and hopefully not at all. Instead, a little lateral thinking can result in a graceful solution, and the solution has become something of an idiom in the J2EE world.

Someone recently asked this question on the JBoss users' mailing list, and several people spewed the cliche: use an MBean to initiate the expensive operations in a Singleton at deploy time. Concise, elegant and totally incomprehensible to the poor bugger asking the question.

Here's a prettified version of the answer I sent him. May it serve you well.

  1. Adjust your stateless session beans to offload the expensive lookup operations to a Singleton. For example, they could invoke a method called getStuff() on the Singleton.

  2. Now factor the expensive operations out of the Singleton's getStuff() into getExpensiveStuff(). In getExpensiveStuff(), store the results in instance variables. Then adjust getExpensiveStuff() so that it uses the stored results when possible, only performing the expensive operations when necessary.

  3. In the Singleton's constructor, invoke getExpensiveStuff().

  4. Now for the MBean. An MBean is a "managed bean", part of the Java Management Extensions (JMX) specification.

    Create an MBean, called ExpensiveStuffWarmup (implementing interface ExpensiveStuffWarmupMBean), for example. Its constructor should instantiate the Singleton, indirectly invoking the Singleton's getExpensiveStuff() method. For convenience, you may want to do this with a warmStuffUp() method exported as part of the management interface, so that you can invoke it via JMX (using JBoss' jmx-console, for example).

    Chapter 2 of the O'Reilly book "Java Management Extensions" provides an excellent introduction to writing your first MBean. I downloaded chapter 2 of this book from somewhere for free a couple of months ago, but can't remember where. I've been sloppy with my notes lately. :-(

    You can view the book online if you have an O'Reilly Safari subscription. If you don't have a subscription, you may be able to view the book anyway with a 14 day trial.

  5. Lastly, create a service deployment descriptor for your MBean and arrange for it to be deployed by your application server. For JBoss, this means creating a JBoss service descriptor file called warmup-service.xml, for example, and placing it in the jboss/server/default/deploy directory.

    The service descriptor file is simple. The trick is in classloading. To keep things simple, I'd put the JAR file containing the Singleton class in jboss/server/default/lib directory, so that it's available to both the MBean and the stateless session bean, which should be deployed somewhere under jboss/server/default/deploy.

    The service descriptor might look like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <server>
       <mbean code="com.example.ExpensiveStuffWarmup" name="example:service=exWarmup">
           <!-- You may need to define dependencies; I haven't never needed to before
               <depends>example:service=exDependent</depends>
           -->
       </mbean>
    </server>
    

This may seem like a lot of work, but keep in mind that you're doing optimization work here. With J2EE, optimization is usually something that focuses outside the business logic domain and its only inside the business logic domain that J2EE is supposed to save you time. Har har, did I pull the one with bells on?

Leave a Reply