EJB and Spring are capable of providing ecosystem for the implementation of business services. EJB is more specific in its purpose whereas Spring brings us a great deal of flexibility. Can the freedom of Spring be dangerous?
Let's assume that we want to implement a typical layered architecture with facade and services.
EJB implementation:
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class ServiceFacade {
@EJB
private ExampleService service;
public void doCoolThing() {
service.execute();
}
}
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ExampleService {
// instance variables
public void execute() {
// method variables
}
// optional setters
}
and potential Spring implementation:
@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class ServiceFacade {
@Autowired
private ExampleService service;
public void doCoolThing() {
service.execute();
}
}
@Service
@Transactional(propagation = Propagation.MANDATORY)
public class ExampleService {
// instance variables
public void execute() {
// method variables
}
// optional setters
}
Both implementations look pretty similar. But there is something more than meets the eye when it comes to concurrent requests. Firstly, let's dig deeper in the case of EJB. When there are concurrent requests, each request is going to be handled by different bean instance that is taken from the pool. I have already written about something similar here. Thanks to that property we are thread safe. However, Spring implementation can be unsafe. Spring introduces the concept of scopes. Default scope for spring beans is 'Singleton' which means that there will be one instance of particular bean within Spring context. Hence, every request will be handled by the same bean instance - it's similar to servlets behaviour - if we use local (stack) variables, we are safe. What if we want to use instance (heap) variables and we do not want to implement thread safety within them? We can change the beans scope to 'Prototype'. However, the following change:
@Service
@Scope("prototype")
@Transactional(propagation = Propagation.MANDATORY)
public class ExampleService {...}
is not enough. ServiceFacade is still singleton and despite the fact that ExampleService is prototype - it will be injected only once - when ServiceFacade is about instantiation. We can also annotate ServiceFacade as prototype, but I do not like that solution. The following implementation is more elegant for me:
@Component
public class ServiceLocator {
@Autowired
private ApplicationContext ctx;
public<T> T getService(Class<T> type) {
return ctx.getBean(type);
}
}
@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class ServiceFacade {
@Autowired
private ServiceLocator serviceLocator;
public void doCoolThing() {
serviceLocator.getService(ExampleService.class).execute();
}
}
Our facade stays singleton and our services are prototypes. ApplicationContext is thread safe so we shouldn't worry about it.
Two particular questions should be answered:
- Are EJBs thread safe?
- Is Spring thread safe?
To sum up, I'd like to say that EJB gives us thread safety out of the box, whereas Spring brings much more flexibility. However great felxibility comes with great responsibility.
Thanks, nice post.
ReplyDeleteGood to hear, mate!
DeleteIt is pretty good explaination.
ReplyDeletehadoop training in chennai
ReplyDeletehadoop training in omr
salesforce training in chennai
salesforce training in omr
c and c plus plus course in chennai
c and c plus plus course in omr
machine learning training in chennai
machine learning training in omr