Thursday, August 6, 2009

When NOT to use Injection in Seam

Seam has a very interesting and quite frankly very powerful and unique methodology for injection in the Java world. There injection methodology is a bit different in Spring in that it is done at method level (and the fact that Seam supports bi-jection as well). The injection works for services and for properties. So take the example below:



@Name("foo")
@Session
public class Foo implements FooService {

@In
UserTO user;

@In
UserService service;

public void process() {
service.run(user);
}
}



Here we are injecting a user and a service and can now have a seam component or a JSF page call this class. In fact they can both call this easily since there is nothing web specific in the definitions by having the transfer object "user" defined on there pages and then calling: foo.process(). The user being used will be injected as well as the service so they both will be accessible by the method.

This class can be a Stateless Session Bean or a POJO, which under normal circumstances could never handle a user specific class level variable. But with Seam it can. Why is this?

Method Level Injection
Simple. Seam intercepts everything at method invocation time. That way this code can work on classes that are usually stateless. Every time this method is called the bi-jection happens. So one can guarantee that multiple calls to the class will have access to the right user object. (based on scope)

Well that's great for transfer objects and domain objects, but what about that service up there? It's getting injected EACH time as well, which is fairly unnecessary. And each time you do it you are adding to the time it takes to run this method. For most web based applications that small overhead of injecting it will not be felt. However, what if you are using Seam to do some batch processing where you want to process multiple items per second. And what if the class you are using injects multiple services. That is where this scenario starts to show fatigue, and takes more time. This is the problem we were recently having at a client, we noticed an appreciable slowness due to this constant bi-jection of services. The time was enough we were processing 5 items per second instead of 10. so what's the answer?

Not Using @In
The answer is relatively simple. If the bean in question is a Stateless Session bean then use the normal @EJB for your services. Remember when using Seam we either define in the ejb-jar.xml or the Session Bean itself that Seam will be intercepting the Session bean. So when you use @EJB your service will still get injected with all the normal Seam bells and whistles; however, this will occur before the bean is given to the caller and not at method invocation time. The previous code would now look like this:




@Name("foo")
@Session
public class Foo implements FooService {

@In
UserTO user;

@EJB
UserService service;

public void process() {
service.run(user);
}
}



And if you using straight POJOs you can still make use of the @Create annotation and do a bit of coding to set the component yourself then. Just use the following to set the service:



Component.getInstance("serviceName")



Using the @EJB annotation not only helps performance but cleans up the code so that you know if you see @In it's for a transfer object that could be changing.