Still Too Many EJBs

10 PM July 15, 2003

A couple of days ago, Hani wrote an entry about on the topic of my Too Many EJBs post. Hani had a couple of good points and a few really bad ones.1 The good points were that I need to ‘join the dots’ in the argument between the list of pros and cons and the article’s conclusion, that I should quantify the meaning behind “a LOT” and that I should explain what “eat memory and CPU cycles for no discernable benefit” means.

I’ve worked on two large J2EE systems. The current one has more than a million lines of source—1.5 million with generated code—and 500 EJBs distributed over twenty or so subsystems. Both this system and the one I worked on previously were designed similarly:

  • Servlets make calls to Stateless Session EJBs designated as “Use Case Controllers”.
  • The Use Case Controllers call a second tier of Stateless Session EJBs.
  • The second tier manipulate data through CMP Entity EJBs or another layer of Stateless Session beans that access files or external systems.2

I know of several other large J2EE systems designed similarly, and none that are very different. But your mileage may vary.

Joining The Dots

Here I explain how I moved from the list of pros and cons to the conclusion that only one EJB per subsystem is required. The ‘first EJB’ is the Use Case Controller EJB that provides access to the subsystem. The “more EJBs” are the ones behind that that actually do the work.

The first part of this argument was that all the advantages of using EJBs are gained with this first EJB:

Pro First EJB More EJBs
Individual EJB-wrapped components can be distributed Defines the component, letting you distribute it. Add no advantages for distribution.
Resource pooling Provides you with hooks into the EJB container’s pooling. Provide you with more hooks, but you only need the one.
Container managed transaction scope Notifies container when you activate the component, so that it can start a transaction Also notify the container, but it doesn’t matter, because EJB transactions can’t be nested.3

If you know of additional benefits, please leave a comment.

The second part of the argument was that the disadvantages accrue with each and every EJB:

Con First EJB More EJBs
More effort to implement Write the bean interface, the home interface, the bean functionality, configure in ejb-jar.xml Do it as many times as you have beans.
More effort to use Requires use of PortableRemoteObject. Must be careful about letting run-time exceptions slip past the EJB (because they cause a rollback, whether you wanted it or not). Must manipulate through an interface that is not implemented by the code you are calling. Multiply by number of beans you have.
Calls take longer Even if in-container, each call incurs small overhead managing the state of EJB and serialising parameters. The more EJBs you have, the more likely you will want to interact with one in a tight loop.
Must use JNDI Use JNDI to get the Home interface, which you need unless you can get a bean reference from elsewhere. More beans means more interactions, means more JNDI.
CMP Entity EJBs With just one EJB, you probably don’t have any. They take more effort to implement, than a roll-your-own persistence layer, let alone a purpose-built Object-Relational mapper.
BMP Entity EJBs Ditto Combine the worst aspects of roll-your-own and Entity EJBs
Stateful Session Beans Session Bean more appropriate as the only EJB in a component. The canonical example of a stateful session bean is the shopping cart, but there are better ways to build a shopping cart.
Configuring Containers If you use EJBs at all, you incur a container configuration cost Additional cost incurred to ensure each EJB has the right JNDI name, transaction attributes, access intent, and any “user” configuration required
Container Eats Memory Container typically requires megabytes of Java code, plus many more megabytes for EJB cache, lookup tables and other internal structures Each EJB brings more generated code, plus additional requirements for the internal memory structures

What “a LOT” Means

I was surprised that anybody who has used EJBs would want this spelled out, but here goes:

  • An EJB takes a LOT more effort to implement than a standard Java object. The “LOT” refers to the two additional interfaces, multiple configuration file entries. and plethora of rules as to what you may or may not do in an EJB or a class called by an EJB.
  • Any EJB takes a LOT more effort to use than a standard Java object. Mostly means that I despise PortableRemoteObject. I have written about this before, though Charles does a more thorough job than I. It also refers to the jumping through hoops to get an object reference, remembering that the parameters may (or may not) be serialized, being careful with runtime exceptions and taking any transactional or access-intent set in the configuration files into consideration.
  • Any call to an EJB takes a LOT longer than a call to a standard Java object. On my EJB container of choice, EJBs have between four and six generated support classes. At runtime, a method invocation on an EJB will traverse at least two of these classes. These support classes make calls to the container support libraries to, at a minimum, activate and deactivate the EJB. The container I use serialises and deserialises each and every parameter, regardless of whether the target EJB is in the same container or not. Compared to making a simple Java method invocation on a real Java object, an EJB method invocation takes a long time.

Eating Memory and CPU Cycles for No Discenerable Benefit

The commercial EJB containers I have used take thirty or forty seconds to come up with only a single EJB deployed. Some of this is initialising Servlet and EJB containers and bringing up essential services like JNDI. The more EJBs deployed, the longer it takes. The application I’m working on takes at least five minutes before it’s good to go.4 At this point, it has consumed 600,000,000,000 CPU cycles and 150,000k of memory, and it still hasn’t done anything useful. Running in development, memory usage levels out at about 250Mb, not much of which can be paged out because of the JVM‘s garbage collection.

Of course, this is a big app, and it requires considerable resources. But with fewer EJBs, it would need less resources to do the same job, reducing start-up time, memory usage and response time.

Final Thoughts

These arguments don’t consider any of the soft issues that surround the construction of a large J2EE system. There are often good non-technical reasons for choosing to use EJBs, and even to use many EJBs. Also, I’m not arguing that existing systems built with “too many EJBs” don’t work or should be rewritten.

What I am advocating is this: if you are building a large J2EE system, think carefully before scattering EJBs willy-nilly through the design.


1 I can’t resist replying to two. First, my original post never advocated one EJB for an entire system. Hani might have understood this, but his writing was unclear enough that at least one of his readers didn’t.

And “l33t php app”? Is that the kind of reasoned, intelligent argument Hani is looking for?

2 Even though accessing system resources in this manner is against the EJB rules.

3 See section 11.1.2 of the EJB 1.1 spec. It is possible to suspend one transaction and start a second one, but this is not typically needed in a commercial application.

4 Ten or twelve in debug mode, longer if the shared database is heavily loaded.

By alang | # | Comments (13)
(Posted to Software Development)
© 2003-2006 Alan Green