Sunday, 17 April 2011

Auto-wiring EJB3 Beans with the Spring SpringBeanAutowiringInterceptor

The usual technique for creating an EJB using Spring is to extend AbstractStatelessSesstionBean and then to use the ContextSingletonBeanFactoryLocator to load your configuration via a beanRefContext.xml file. You would then load your Spring beans by overriding onEjbCreate():

@Stateless(name = "SpringWineSearchFacade", mappedName = "SpringWineSearch")
public class WineSearchFacadeBean extends AbstractStatelessSessionBean implements WineSearchFacade {

  @Override
 
public void setSessionContext(final SessionContext ctx) {

   
try {
     
super.setSessionContext(ctx);
     
this.setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
     
this.setBeanFactoryLocatorKey(SERVICE_BEAN_FACTORY);
   
} catch (Exception e) ... etc.
 

  @Override
 
protected void onEjbCreate() throws CreateException {

   
logger.info("FlowControl EJB -- onEJBCreate() --- Entry");
    flowControlService =
(FlowControlService) this.getBeanFactory().getBean(SERVICE_BEAN);
    incidentReporter =
(IncidentItf) this.getBeanFactory().getBean(INCIDENT_REPORTER);
    logger.info
("FlowControl EJB -- onEJBCreate() --- Exit");
 
}


A possibly newer and more convenient technique for EJB3 is to auto-wire your beans using the org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor class. This can either be applied using the @Interceptor annotation as shown below, or by using the interceptor-binding XML element in your EJB deployment descriptor file.

@Interceptors(SpringBeanAutowiringInterceptor.class)
@Stateless(name = "SpringWineSearchFacade", mappedName = "SpringWineSearch")
public class WineSearchFacadeBean implements WineSearchFacade, WineSearchFacadeLocal {

 
/** automatically inject the bean that is our delegate object */
 
@Autowired
 
private WineServiceImpl wineService;

 
@Override
 
public WineList wineSearch(WineCountry country) {
   
// Use the delegate class
   
return wineService.getWineByCountry(country);
 
}
etc...

SpringBeanAutowiringInterceptor loads its Spring context using a ContextSingletonBeanFactoryLocator in a similar fashion to that described above. The major difference here is that it can only load the default beanRefContext.xml file and that file can only contain a single context definition. This is because it’s loaded by type and not by name / id.
<?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-3.0.xsd  
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 <!-- This context is loaded by type and not by name -->
 <bean class="org.springframework.context.support.ClassPathXmlApplicationContext">
        <constructor-arg value="classpath:appConfig.xml" /> 
   </bean>

</beans>
Notice that the EJB facade delegates to a service bean annotated with @Autowired. This tells the SpringBeanAutowiringInterceptor where to inject the service/delegate bean. In this example, we’re again injecting by type rather than name / id.

Having sorted out your EJB, you also need to configure the Spring auto-wiring and I prefer to do this using annotations rather than XML config. The first step here is to get Spring to scan for auto-wire compatible beans and this is done by adding the following line to your Spring XML config file:

<context:component-scan base-package="marin.tips.ejb3.stateless.springexample_winesearch" />
This line tells Spring to scan your Java classes starting at the base-package location for any classes annotated with @Component and hence the final step in this task is to apply @Component to all beans that you wish to auto-wire.

@Component
public class WineServiceImpl implements WineService {
etc...

There are pros and cons to both of these methods, for example, using the interceptor means that you create a lot less boilerplate code, but using auto-wiring means that you’re limited to injecting classes that you have marked with the @Component annotation. Furthermore, one benefit of using XML base dependency injection over auto-wiring is that with XML you have your DI defined in one central location (or one location per JAR/module depending upon the size and complexity of your project).

1 comment:

Mederu said...

thanks great bloag