Sunday, March 28, 2010

What’s so wrong with EJB’s?

It’s not that they are heavy. It’s not that they are difficult to write. So, what’s wrong with EJB’s?

EJB’s can be either Stateless, Stateful or Singleton. However, when you are working on a web environment for example, these lifecycles will not suffice. Request, session and application lifecycles would be much better suited in that case. Another example is a business process application, where you could have a task or a process lifecycle; again, EJB’s will not match those lifecycles. This is what I call the Lifecycle Mismatch.

Through the years, EJB’s have become more POJO-like, through the use of annotations and without requirements such as XML descriptors and Java interfaces. However, it doesn’t matter how simple they get, until they don’t remove the lifecycle restriction, you will end up creating additional layers in your application and different component models to adapt your required lifecycles.

Note: The lifecycles I’m referring are also known as contexts or scopes in other frameworks/specifications.

For example, take a look at JSF. They introduced the JSF Managed Beans to handle this problem. JSF Managed Beans can be bound to request, session or application contexts. From there, you are on your own on how you connect them to the EJB’s different lifecycle.

CDI (Contexts and Dependency Injection) is a specification, part of the JEE stack, that is trying to fill that gap. It provides dependency injection and lifecycle management to POJO’s and EJB’s. But providing lifecycle management to EJB’s doesn’t feels right, because they already provide their own. CDI does its best effort to accommodate this mismatch.

On the other hand, CDI could provide to POJO’s, all the services EJB’s currently have, through extensions. So, do we really need EJB’s? Well, not really! You can check my post EJB’s - Time to let them go? for more information.

Conclusion

EJB’s have become light weighted and easy to write. But the lifecycle mismatch is still there. POJO’s, on the other hand, don’t have this restriction and, with CDI, they could have all the services EJB’s currently provide.

24 comments:

mojavelinux said...

I agree that a POJO, which in spec terms is referred to as a managed bean (not to be confused with a JSF managed bean), should get all the same core services of EJB (transactions, persistence, async, startup), just minus the HA stuff (clustering/replication, pooling, timers, concurrency). The HA additions are really what really define an EJB, IMHO.

However, I think you may have the situation with the lifecycle confused. You are correct that this was all screwed up in the past. But Java EE 6 is different. It's not just an attempt.

Let's drop stateless and singleton for a second. The stateful session bean (SFSB) is everything you are asking for. CDI provides the lifecycle scoping, binding the reference to the designated context (request, conversation, session, application or custom scope). Once the context ends, the instance is destroyed.

Stateless EJBs do have a different context...no context. They are just pools of instances and that is something you need EJB for, because it isn't something the client/application is going to maintain.

You could argue the same thing for singletons. They are similar to application-scoped beans, except that you are guaranteed to only have a single instance even in a cluster (I'm mostly certain).

So yes, stateless and sington session beans do have their own lifecycle, but it's expected that they do. Most of your application beans will be SFSB (or, as we established at the beginning, just POJOs). In terms of aligning the lifecycle of your beans with the scopes in your application, what you really want are SFSB with a CDI scope. In fact, you just don't use SFSB without getting CDI involved anymore. They are baked together.

mojavelinux said...

And, btw, JSF managed beans are dead. Don't use them anymore. And tell your friends ;)

mojavelinux said...

To sum up, what I hope I've been able to clarify for you is that CDI isn't layering lifecycle management on top of lifecycle management that a SFSB already has. CDI *is* the lifecycle management for a SFSB. They are one and the same.

mojavelinux said...

I'm thinking perhaps we should have a short section in the Weld documentation that addresses this question. I'm glad that you raised it, because I'm sure others are confused about this as well.

Germán Escobar said...

Hey Dan, thanks for your comment! Yes, JSF Managed Beans are dead, although they still exist and is very confusing for developers (duplicated @...Scoped annotations). I'm sure this will be addressed in future versions. I used them only as an example of the lifecycle problem EJB's introduced.

I think you're proving my point. I agree with you that CDI works great with SFSB, but they are not the whole EJB specification. Your "let's drop stateless and singleton for a second" statement is not there for nothing. Maybe, I should have delved deeper on this.

I don´t agree with your point on Stateless EJB's. It depends on the context you are working on. You can use the request scope and, if the object is to expensive to be created each time, there should be a @Pooled annotation or something like that you could easily control. Although, I would say, that with a good design, you shouldn't need it. Anyway, the point is that they provide their own lifecycle which is wrong. The same for Singletons.

NBW said...

I think EJBs are still valuable for remote interface usage otherwise use CDI.

mojavelinux said...

Likely what will happen with the future of the JSF scope annotations is that they will become aliases to the CDI scopes. We are already implementing this in the Seam Faces Module as a prototype/concept.

@NBW, yes, I left out the remoting aspect of EJBs. That is indeed another unique characteristic.

@German, in a way the @Stateless annotation is the same as @Pooled. It's just a matter of who is doing the pooling. We could certainly implement pooling as a portable extension to CDI (the extension SPI is another important aspect of CDI that helps close the gap you point out). The same could be said for singleton.

Here is what I propose moving forward. We can implement your ideas for @Pooled and @Singleton (w/o EJB) as CDI portable extensions (hopefully in Seam) and we'll see how that compares or sets to replace EJB.

I still believe that you choose EJB because it handles concerns you would otherwise need a library/bean container to provide. Perhaps there is a mismatch between scoped beans and stateless/singleton session beans, but I still say that's because the latter two are not scoped beans. Stateless is not scoped (though could be a dependent of another scoped bean) and singleton is singly scoped.

As for whether you need stateless beans, hey, maybe you don't need them ;)

I think what we really do need is for managed beans to have the services that we use every day, especially transactions.

Scott Ferguson said...

Actually, in Resin we treat Stateless, Stateful and Singleton beans as special cases of CDI beans, where a Stateless bean is essentially a pooled CDI bean, and our plain CDI beans support all the EJB annotations like the XA annotations. (So our own philosophy is very much like what you've written.)

I wouldn't say the EJB lifecycles are "wrong" exactly, but they're a specialized lifecycle that does not apply everywhere.

Anonymous said...

Well, whats wrong with EJB? Who cares? Rails has killed it along with Sun Microsystems.

Anonymous said...

EJB alone is not intended to solve this problem.

You have to mix it with CDI/Seam instead.

I would like to see your comment after you try JavaEE6 out (EJB3.1 + CDI + JSF2).

Germán Escobar said...

@mojavelinux, sure, it is a great idea to implement that as portable extensions. I think the trend will be that: providing EJB services, which are great, to POJO's.

@Scott, hey, I'm glad to hear this, I think you guys are doing an excellent job with Resin and are moving definitely towards the right direction.


The thing is that is not right for a Component Model to provide its own lifecycle management. Fortunately, SFSB works great with CDI, but the story could have been very different.

Reusability is one of the key concepts that is affected when a Component Model introduces its own lifecycle management. You can only use it if your use case matches that lifecycle. It will work in some cases though. That's what I like about CDI. It doesn´t adds a new Component Model, it manages the lifecycle of other component models. But it cannot do anything if the component model introduces it's own lifecycle. Again, fortunately, it works well with SFSB's at least.

I do use EJB3.1 + CDI + JSF2 and it works great once you know how it works. But people invest a lot of time learning EJB's and then you have to tell them ... ehhh, I'm sorry, don't use Stateless or Singleton ... ahh, and please use @Inject, not @EJB, unless ... etc, etc. That is very confusing for new developers.

When people are presented with so many choices, they just stop using the technology and move forward to something else. And it is not like we are compromising flexibility here.

exitcondition said...

Interesting post, German, but I think we're getting hung up on names for scopes rather than what they represent.

EJB is an application-layer technology. When used from a Web context, the webapp becomes the client of the EJB. And in EJB, the client manages the start and end of conversational state.

So the Stateful Session Bean session starts on lookup or injection of the proxy (in JBoss anyway), and ends when the client calls a @Remove method. This can be used to create conversational contexts for N invocations within a web request, or even spanning many requests. Thus you can store a SFSB proxy in the page, request, or session and use it safely until done.

SLSB is nice because the client has no session to manage, and if all state is accounted for in the invocation, we get high performance as the server does not have to keep a 1:1 relationship between active clients and bean instances.

And of course Singleton is an application-shared context with lifecycle listeners.

So to me you just need to map EJB (application) lifecycle to that of your webapp (client). :)

S,
ALR

Les said...

Hmmm...you must not have been around when EJBs were introduced. At the time, corba was the dominant model. Corba (and the original EJB) tried to model the lifecycle. Persistent objects were distributed, logic components had state, etc. This matched up really well to the web model. Unfortunately, they had massive problems making it scale.

The original intent of EJB was around stateful beans (stateless was an afterthought). These were supposed to be your "process lifecycle" beans. Unfortunately, they fell out of favor when we all learned that they only way to scale applications to internet size was with the removal of state.

So, while I agree that the mismatch is a leaky abstraction, it is necessary. You see, the only reason to have the ejb layer at all is to scale. If you don't need to scale, there is no reason to have an application server between the web server and the data repository. By making the EJBs stateful, they won't scale. Thereby, making them useless. Kinda a catch 22. :)

mojavelinux said...

I agree that the @EJB annotation is no longer needed. That's what I refer to as left over dust after the carpentry work that went into reshaping Java EE. @Inject is the new @EJB (with some subtle, but important differences).

Germán Escobar said...

Hey Andrew! Thanks for your comment! That mapping between the client and application is really what this is all about. EJB's force you to a given architecture where you need to map somehow the lifecycle you are working on (call it web, bpm, seda, or whatever) to match the EJB's lifecycle. Now, I'm not saying that is a bad idea, but it is imposing you a restriction beforehand. It just feels so 2002.

@Les, talking about leaky abstractions, I thing that sometimes developers just use EJB's to follow the trend. I think the control should be more fine grained where you could say like I want this POJO to be @Synchronized, @Transactional, @Clustered, @Restricted(...), etc. And maybe a stereotype @EJB to have them all. BTW, you are right about the state for massive applications. It's still the only way when you need to scale to hundreds of servers.

@mojavelinux, in fact, I'm writing a new post to explain better those kind of things people might get confused with, including @Inject vs @EJB, the different singleton flavors, the duplicated scopes and the @ManagedBean vs @Named annotations. If you (or anyone) have another to add, be my guest!

exitcondition said...

Ah German, but EJBs are a component model for applications. Not necessarily web applications. To provide the mapping by spec would be overstepping EJB's bounds, 2002 or 2010.

This is where higher-level stuff comes into play within the JEE platform. From there we can wire up EJB/Web quite nicely and with minimal plumbing code required by the application developer. JEE6 does a fantastic job there (over previous revisions), and EJB is not to blame for leaving it out. :)

S,
ALR

Germán Escobar said...

Andrew, I'm not saying that the mapping should be provided by the spec. I'm saying there should be no mapping at all. EJB's should let others decide how the lifecycle of the component should be ... just like the humble POJO's ;)

One problem that came into my mind the other day regarding CDI and SFSB is that if a runtime exception (not marked as application exception) is thrown from the SFSB, the SFSB is discarded and the state is lost. This will cause a lot of trouble to some people!

@mojavelinux. Reading the EJB spec the other day, I found the following for Singletons:

"In cases where the container is distributed over many virtual machines, each application will have one bean instance of the Singleton for each JVM".

It seems that replication at the application level is still a problem.

Heinz said...

I'm confused about stateless EJBs in connection with CDI. I made a small Application (Web- and Businesstier) to test some behavior. When I inject (@inject) from a JSF ManagedBean (@Named, @RequestScope) an EJB (@Named, @Stateless), I get every time I call the EJB the same reference. So when I store some value in this (stateless) Object, it doesn't get lost. When I inject inside the same Application through an other JSF ManagedBean(@Named, @SessionScope) the stateless EJB, I get also the same reference with the stored value back. So I'm confused!

It looks like, that a stateless-EJB act as a singelton, is it possible?
I would expect that the stateless Bean doesn't save any states (or loss it, after calling) and just pool a amount of the same object?

xiao said...

Romantic pink is a tender pretty girl can best embody the links of london color; the stars also began to become followers of links london pink. The summer of passion and energy links of london bracelet and romanticpink, aroused a sweet and romantic agitation. See below nine groups sweetie bracelet pink star.

gabriel! said...

Germán I strongly disagree in some points you made about EJBs. If you have developed big enterprise applications, you should have definitely seen their benefits. First of all, transaction support, locking and the timer service are something to consider. It's difficult to implement declarative transaction support without resorting to a framework like Seam (Should that be changed? yes! Let's hope the improve that in the future).
Also, SLSB are indeed Stateless, so they don't need Context. Why would you want Context if you don't have State, it doesn't make any sense. Being stateless is what allows the application server to pool them and proxy them so that they are easily clustered and reusable components.
Saying that Stateless EJBs don't fit in the lifecycle because of their context management is like saying we should stop using screwdrivers to cut our meat. I mean, SLSB serve a different purpose.
What about web services? There's another example of their use.
EJBs are also natural facades for persistence.

Eric Kizaki said...

EJBs, JEE6, and Seam are garbage. Declarative transactions are hella easy with Spring. Just use @Transactional. I never use any of this complicated crap. Just POJOS and mark some beans as @Component, @Repository, etc. Done. Seam has too much state and complicated garbage you don't need.

Anna said...

Great and Useful Article.

J2EE Training

Java EE course

Java EE training

J2EE training in chennai

Java J2EE Training Institutes in Chennai

Java J2EE Training in Chennai

Java EE training

Java Interview Questions

Devi.Angularjs said...

Java Training Institutes Java Training Institutes
JSF Training Institutes in Chennai JSF Training Institutes in Chennai Java EE Training Institutes in Chennai Java EE Training Institutes in Chennai J2EE Training Institutes in Chennai J2EE Training Institutes in Chennai | Core Java Training Institutes in Chennai

Devi.Angularjs said...

Hibernate Training Institutes in ChennaiHibernate Training Institutes in Chennai Hibernate Online Training Hibernate Online Training Hibernate Training in Chennai Hibernate Training in Chennai Java Online Training Java Online Training

Post a Comment