JavaEE 5, Spring 2 and AspectJ 5: dependecy injection magics
JavaEE 5, Spring 2 and AspectJ 5: dependecy injection magics
After the Filippo disillusion about Java EE 5 dependecy injection I decided to study the problem of integrating dependecy injection capabilities provided by Java EE 5 and those provided by the Spring framework.
The challange is the following: let's assume that a Stateless EJB, let's say "TestEJB", needs the injection of two POJOs, let's say "TestBean1" and "TestBean2", using two different policies: using JNDI (via @Resource annotation) or without JNDI.
The test EJB and the two test beans implements the following interface:
@Local @Remote
public interface Test {
public abstract String doTest();
}
The two beans just print out a message and return it; let's show TestBean1 (TestBean2 is similar)
public class TestBean1 implements Test {
public String doTest() {
String message = "=>TestBean1";
System.out.println(message);
return message;
}
}
Now let's assume that the TestEJB needs to be injected of instances of TestBean1 and TestBean2 in order to print out and return a message partially composed by TestBean1 and TestBean2:
@Stateless
public class TestEJB implements Test {
public String doTest() {
String message = "=>TestEJB";
System.out.println(message);
return message + "(" + testBean1.doTest() + "," + testBean2.doTest()
+")";
}
@Resource(name="beans/TestBean1")
private Test testBean1;
private Test testBean2;
public void setTestBean2(Test testBean2) {
this.testBean2 = testBean2;
}
}
In order to allow the injection of TestBean1 into TestEJB I found the following solution: let's assume that TestBean1 is defined in the Spring application context as follows:
<bean id="TestBean1" class="test.TestBean1" />
Now let's populate the JNDI with entries that allow the instantiation of test beans using Spring. I used the following class:
public class SpringBeanFactory implements ObjectFactory {
private static ApplicationContext appContext;
private static final String BIND_NAME_PREFIX = "beans/";
public static void populateJNDI(ApplicationContext appCtx) {
appContext = appCtx;
try {
Context ctx = new InitialContext();
String beansDef[] = appCtx.getBeanDefinitionNames();
for (int i = 0; i < beansDef.length; i++) {
Class beanClass = appCtx.getType(beansDef[i]);
String bindName = BIND_NAME_PREFIX + beansDef[i];
Reference reference = new Reference(beanClass.getName(),
new StringRefAddr(bindName,beansDef[i]),
SpringBeanFactory.class.getName(), null);
ctx.rebind(bindName, reference);
}
} catch (Exception e) {
throw new RuntimeException("Unable to populate JNDI from
application context", e);
}
}
public Object getObjectInstance(Object reference, Name name, Context nameCtx,
Hashtable, ?> environment)
throws Exception {
String beanName = (String) ((Reference) reference).get(0).getContent();
return appContext.getBean(beanName, Object.class);
}
}
The method "populateJNDI" needs to be invoked with the Spring ApplicationContext instance, for example in the "init" method of a Servlet:
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public TestServlet() {
super();
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws
ServletException, IOException {
StringBuffer buf = new StringBuffer();
buf.append("<html>");
buf.append("<body>");
buf.append("Hello from Servlet");
buf.append("<br/>");
buf.append("Hello from chain: ");
buf.append(testEJB.doTest());
buf.append("</body>");
buf.append("</html>");
res.getOutputStream().write(buf.toString().getBytes());
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
ApplicationContext c =
WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
SpringBeanFactory.populateJNDI(c);
}
@EJB
protected Test testEJB;
}
That's all, the TestBean1 is avaiable for injection to EJBs using the @Resource(name="beans/TestBean1") annotation.
Now the second problem: I want to inject TestBean2 into TestEJB without registering the the bean into JNDI.
The solution uses Spring 2 integration with AspectJ. Let's assume that in the Spring application context is defined the following:
<aop:spring-configured/>
<bean id="TestEJB" class="test.TestEJB" lazy-init="false">
<property name="testBean2">
<bean name="TestBean2" class="test.TestBean2"/>
</property>
</bean>
Now let's add a Spring2 @Configurable annotation to TestEJB:
@Stateless
@Configurable("TestEJB")
public class TestEJB implements Test {
...
}
That's all, by compiling the TestEJB with AspectJ using the "spring-aspects.jar" aspect library provided by Spring2, the TestBean2 will be injected into TestEJB.
( Jan 27 2006, 06:01:20 PM CET ) Permalink Comments [1]