EJB3 façade over Spring services
Join the DZone community and get the full member experience.
Join For Free
Context
I recently got my hands on an application that had to be migrated from a proprietary framework, to more perennial technologies. The application consists of one web-front office and a Swing back-office. The key difficulty was to make the Swing part communicate with the server part, since both lives in two different network zones, separated by a firewall (with some open ports for RMI and HTTP). Moreover, our Security team enforces that such communications has to be secured.The hard choice
The following factors played a part in my architecture choice:- My skills, I've plenty more experience in Spring than in EJB3
- My team skills, more oriented toward Swing
- Reusing as much as possible the existing code or at least interfaces
- Existing requirement toward web-services:
- Web services security is implemented through the reverse proxy, and its reliability is not the best I've ever seen (to put it mildly)
- Web services applications have to be located on dedicated infrastructure
- Mature EJB culture
- Available JAAS LoginModule for secure EJB calls and web-services from Swing
Design
To ease the design to the maximum, each Spring service will have exactly one and only one EJB3 façade, which will delegate calls to the underlying service. Most IDEs will be able to take care of the boilerplate delegating code (hell, you can even use Project Lombok with @Delegate - I'm considering it). On the class level, the following class design will be used:

This is only standard EJB design, with the added Spring implementation. On the module level, this means we will need a somewhat convoluted packaging for the service layer:
- A Business Interfaces module
- A Spring Implementations module
- An EJB3 module, including remote interfaces and session beans (thanks to the Maven EJB plugin, it will produce two different artifacts)
How-to
Finally, developing the EJB3 façade and injecting it with Spring beans is ridiculously simple. The magic lies in the JavaEE 5 Interceptors annotation on top of the session bean class that references the SpringBeanAutowiringInterceptor class, that will kick in Spring injection after instantiation (as well as activation) on every referenced dependency. The only dependency in our case is the delegate Spring bean, which as to be annotated with legacy @Autowired.
import javax.ejb.Stateless; import javax.interceptor.Interceptors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor; import ch.frankel.blog.ejb.spring.service.client.RandomGeneratorService; @Stateless @Interceptors(SpringBeanAutowiringInterceptor.class) public class RandomGeneratorBean implements RandomGeneratorService { @Autowired private ch.frankel.blog.ejb.spring.service.RandomGeneratorService delegate; @Override public int generateNumber(int lowerLimit, int upperLimit) { return delegate.generateNumber(lowerLimit, upperLimit); } }
In order to work, we have to use a specific Spring configuration file, which references the Spring application context defined in our services module as well as activate annotation configuration.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <context:annotation-config /> <bean> <constructor-arg> <list> <value>classpath:ejb-service.xml</value> </list> </constructor-arg> </bean> </beans>
Warning: it's mandatory to name this file beanRefContext.xml and to make it available at the root of the EJB JAR (and of course to set the Spring service module as a dependency).
Conclusion
Sometimes, you have to make some interesting architectural choices that are pertinent only in your context. In these cases, it's good to know somebody paved the road for you: this is the thing with EJB3 façade over Spring services. To go further:- Spring documentation regarding EJB 3 injection interceptor
Opinions expressed by DZone contributors are their own.
Comments