Extend EJB 3 dependency injection with Spring 2.0
The general idea of extending the DI capabilities provided by Java EE 5 with those of the Spring 2.0 has already been described by Maurizio Albari in his blog post. Nevertheless there is one aspect in Maurizio's approach that I wanted to overcome: You need to have some kind of vehicle to start your Spring application context with the AspectJ BeanConfigurer? before your EJB 3 beans are initialized and this has been solved by loading the application context with an additional servlet. So that approach forces you to have a web app with at least one servlet in your ejb application.
After doing a little bit of investigation I found a solution which keeps your EJB 3 application web app free and does not introduced any API dependencies into your EJB implementations.
For now this approach is JBoss specific. Basically you need to implement an JBoss EJB 3 service extension to load the application context. A basic implementation follows:
@Service
@Management(ContextLoaderManagement.class)
public class ContextLoaderService implements ContextLoaderManagement {
private static final Log LOG = LogFactory.getLog(ContextLoaderService.class);
/** Currently no loading strategy implemented */
private static final String CONTEXT_FILE_NAME = "classpath:/META-INF/applicationContext.xml";
/** Spring BeanFactory containing the AspectJ BeanConfigurer*/
private ConfigurableApplicationContext context = null;
// Lifecycle methods
public void start() throws Exception {
LOG.info("Called start");
this.context = new ClassPathXmlApplicationContext(CONTEXT_FILE_NAME);
}
public void stop() {
LOG.info("Called stop");
this.context.close();
}
}
Next step is to define that your EJB stateless session bean implementation depends on the above service.
@Stateless
@Depends("jboss.j2ee:jar=userService.jar,name=ContextLoaderService,service=EJB3")
@Configurable(value="userService")
public class UserServiceImpl implements UserServiceLocal, UserServiceRemote {
private static final Log LOG = LogFactory.getLog(UserServiceImpl.class);
private UserDao dao;
public UserServiceImpl() {
LOG.info("Called constructor");
}
public void saveUser(User user) {
this.dao.saveUser(user);
}
public User getUser(Long id) {
return this.dao.getUser(id);
}
public void setDao(UserDao dao) {
this.dao = dao;
LOG.info("Called setDao with [" + dao + "]");
}
}
After compiling the UserServiceImpl using the AspectJ compiler and the following applicationContext.xml your application will be configured by Spring.
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:spring-configured/> <bean id="userService" abstract="true"> <property name="dao" ref="userDao"/> </bean> <bean id="userDao" class="org.springframework.test.dao.UserDaoImpl" /> </beans>
This approach is certainly not as generic as I would like to have it. But as time emerges I think solutions for other EJB 3 enabled application server will come up.
Download in other formats:
