Spring and EJB integration

springejbEJB components differ from Spring beans on the technical background whereas their concept is quite similar. The technical diversity might be an issue when composing dependencies between these two bean types. The purpose of this post it to give an idea to design solutions based on a mutual EJB and Spring beans interoperability. There are taken into account two main concerns: accessing EJB components from Spring beans and accessing Spring beans from EJB components. The post introduces technical aspects referring to a simple enterprise application implementing beans cooperation.

Background

We rely here on EJB 3.1 and Spring Core Framework 3.0 versions. The aim is to consider interoperability between these kind of components which are likely to be used in real solutions and also which make sense to link. These are the following EJB components: Stateless Session Bean (SLSB), Stateful Session Bean (SFSB), Singleton Session Bean and Message Driven Bean (MDB). On the Spring side, there are taken into account beans with singleton scope. Spring Framework works well with his components and also provides some kind of support to use EJB components. The official reference [1] mentions mainly accessing Spring Singleton Beans from EJB SLSB and accessing EJB SLSB from Spring Singleton Beans [2]. The reference document [3] also writes about possible problems which are faced in Troubleshooting section. Generally speaking, Spring and EJB beans interoperability should be especially considered when one them comes from a legacy side.

1. Simple Enterprise Application

Business point of view (use case)

A business user can perform money transfer operation passing a number representing certain amount of money. In addition to this, a business user can also check available account balance.

There is provided a Java EE application to meet the use case’s requirements. The whole application consists of two parts:

  1. Server module which delivers business services
  2. Web client which uses these services

Technical point of view

The application consists of two tiers:

  1. Business logic tier which exposes available services through MoneyTransferFacade interface.
    In order to provide those services, the MoneyTransferFacade implementations use internally implementations of MoneyTransferService interface. The MoneyTransferService interface and his implementations exist in business logic tier below the MoneyTransferFacade. In other words, business logic tier is composed from two layers: façade layer represented by MoneyTransferFacade and service layer represented by MoneyTransferService. There are provided EJB and Spring implementations of façade and service layers.
  2. Web tier which is represented by servlet component MoneyTransferServlet; it is the web client of a business logic tier (communication by MoneyTransferFacade interface).

Application has the Maven structure and contains the following artifacts:

  1. com.softexploration.lab.ejbspring.transfer.app – EAR module; assembles the whole application into an EAR; technical name of this JEE application.
  2. com.softexploration.lab.ejbspring.transfer.webapp – this artifact provides MoneyTransferServlet which fulfills defined business use case. It refers to façade implementations: com.softexploration.lab.ejbspring.transfer.facade.ejb and com.softexploration.lab.ejbspring.transfer.facade.spring.
    The servlet allows to select (by predefined names) both façade and service implementations to perform use case’s actions.
  3. com.softexploration.lab.ejbspring.transfer.facade – this artifact defines façade interface to communicate with com.softexploration.lab.ejbspring.transfer.webapp.
  4. com.softexploration.lab.ejbspring.transfer.facade.ejb – this is the EJB implementation of com.softexploration.lab.ejbspring.transfer.facade which uses internally com.softexploration.lab.ejbspring.transfer.service.spring; it illustrates an example of accessing Spring beans from EJB.
  5. com.softexploration.lab.ejbspring.transfer.facade.spring – this is the Spring implementation of com.softexploration.lab.ejbspring.transfer.facade which uses internally com.softexploration.lab.ejbspring.transfer.service.ejb; it illustrates an example of accessing EJB beans from Spring beans.
  6. com.softexploration.lab.ejbspring.transfer.service – this artifact defines service interface to communicate with façade’s implementations.
  7. com.softexploration.lab.ejbspring.transfer.service.ejb – this is the EJB implementation of com.softexploration.lab.ejbspring.transfer.service.
  8. com.softexploration.lab.ejbspring.transfer.service.spring – this is the Spring implementation of com.softexploration.lab.ejbspring.transfer.service.
  9. com.softexploration.lab.ejbspring.transfer.build – auxiliary artifact to build this project.

Figure 1: Component diagram of the Simple Enterprise Application

The dependencies between artifacts are illustrated in Figure 1. Intermediate artifacts representing interfaces (com.softexploration.lab.ejbspring.transfer.facade, com.softexploration.lab.ejbspring.transfer.service) are here omitted. There are shown direct dependencies between artifacts representing concrete implementations. The implementation artifacts informs us which interfaces they offer and which they require. For example, the EJBMoneyTransferFacade in the com.softexploration.lab.ejbspring.transfer.facade.ejb provides implementation of MoneyTransferFacade interface and at the same time requires dependency to the MoneyTransferService.
The diagram informs about one EJB and one Spring implementation of the MoneyTransferFacade interface. In regard to the MoneyTransferService interface, there is one Spring implementation and three EJB implementations.

Note

In further article’s parts will be partially presented source code with an emphasis put on the most significant snippets. I encourage to download the whole source and explore [1].

Common base code overview

// […]
public interface MoneyTransferFacade {

	/**
	 * Transfer money based on <code>request</code> data.
	 *
	 * @param request
	 * @return operation response
	 */
	MoneyTransferResponse transfer(MoneyTransferRequest request);

	/**
	 * Get current available balance.
	 */
	Double getBalance();
}

Figure 2: com.softexploration.lab.ejbspring.transfer.facade.MoneyTransferFacade

// […]
public interface MoneyTransferService {

	/**
	 * Transfer money based on <code>request</code> data.
	 *
	 * @param request
	 * @return operation response
	 */
	MoneyTransferResponse transfer(MoneyTransferRequest request);

	/**
	 * Get current available balance.
	 */
	Double getBalance();
}

Figure 3: com.softexploration.lab.ejbspring.transfer.service.MoneyTransferService

// […]
public class BaseMoneyTransferService implements MoneyTransferService {

	private Double balance;
	public void setBalance(Double balance) {
		this.balance = balance;
	}
	public Double getBalance() {
		return balance;
	}
	public MoneyTransferResponse transfer(MoneyTransferRequest request) {
		balance = balance - request.getAmount();
		return new MoneyTransferResponseImpl(balance);
	}
}

Figure 4: com.softexploration.lab.ejbspring.transfer.service.impl.BaseMoneyTransferService

There is provided a base implementation of MoneyTransferService in class BaseMoneyTransferService presented in Figure 4. This implementation is then extended by EJB and Spring implementations.

Build and deployment

System requirements:

  1. JEE 6+ JDK
  2. Spring Core Framework 3
  3. Apache Maven 3
  4. JEE 6+ compliant application server

It was developed and ran using followings:

  1. Oracle JDK javac 1.7.0_01
  2. Spring Core Framework 3.2.2.RELEASE
  3. Apache Maven 3.0.3
  4. Oracle WebLogic Server Version: 12.1.2.0.0 and Apache TomEE+ 1.5.2

In order to build this application:

  1. Go to com.softexploration.lab.ejbspring.transfer.build artifact location on a command line and execute: mvn clean install
  2. Under location of com.softexploration.lab.ejbspring.transfer.app in the target folder will be created  a ready to deploy application: com.softexploration.lab.ejbspring.transfer.app-0.0.1-SNAPSHOT.ear

Deployment:

Deploy the com.softexploration.lab.ejbspring.transfer.app-0.0.1-SNAPSHOT.ear on a JEE 6+ compliant application server. The artifact does not declare external dependencies.

Accessing deployed application:

The MoneyTransferServlet takes two GET parameters:

  1. amount – amount of money to transfer; expressed in java.lang.Double
  2. facade – name of a façade to perform a transfer

There are following façade names:

  1. ejb-spring – EJB façade which refers to Spring Service
  2. spring-singletonejb – Spring façade which refers to Singleton Session Bean Service
  3. spring-slejb – Spring façade which refers to SLSB Service
  4. spring-sfejb – Spring façade which refers to SFSB Service

Generic URL:

http://<host>:<port>/webapp/MoneyTransferServlet?facade=<facade-name>&amount=<amount-value>

<host> – host on which application server is running
<port> – port of application server
<facade-name> – façade name
<amount-value> – amount to transfer

Example URLs:
http://localhost:7001/webapp/MoneyTransferServlet?facade=ejb-spring&amount=100.5
http://localhost:7001/webapp/MoneyTransferServlet?facade=spring-singletonejb&amount=100.5
http://localhost:7001/webapp/MoneyTransferServlet?facade=spring-slejb&amount=100.5
http://localhost:7001/webapp/MoneyTransferServlet?facade=spring-sfejb&amount=100.5

A result of invocation can look like:
current balance: 2000.0
amount to transfer: 100.5
transferring…
transfer finished
current balance: 1899.5

2. Accessing Spring beans from EJB

A general approach

EJB since version 3.0 and Spring version 2.5 taken together allow inject through @Autowired mechanism Spring bean into EJB component by the org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor assigned to the EJB. It means that EJB component needs to declare a dependency to the required type and annotated it with @Autowired. The SpringBeanAutowiringInterceptor must be specified on the EJB class level interceptors declaration.

The SpringBeanAutowiringInterceptor obtains target beans defined in a spring application context in the beanRefContext.xml file which is expected to be on an application classpath [2].

It can be summarized in the steps:

  1. Define Spring bean and make it available in the beanRefContext.xml
  2. Define EJB with a dependency to Spring bean type and annotate it @Autowired
  3. Declare SpringBeanAutowiringInterceptor as the EJB class interceptor

Simple Enterprise Application overview

We possess in the example application the MoneyTransferService and the Spring implementation – SpringMoneyTransferService which has to be accessible in the EJBMoneyTransferFacade. There is considered a case when Stateless Session Bean refers to Spring Service Component with singleton scope. In the exactly same way Spring Service Component can be injected into Stateful Session Bean, Singleton Session Bean and Message Driven Bean as well. SLSB is here only for example purposes.

// […]
@Service
public class SpringMoneyTransferService extends BaseMoneyTransferService {
}

Figure 5: com.softexploration.lab.ejbspring.transfer.service.spring.impl.SpringMoneyTransferService

<!-- […] -->
<bean id="springMoneyTransferService" class="com.softexploration.lab.ejbspring.transfer.service.spring.impl.SpringMoneyTransferService">
 <property name="balance" value="${initialBalance}" />
</bean>
<!-- […] -->

Figure 6: com.softexploration.lab.ejbspring.transfer.service.spring/src/main/resources/META-INF/com.softexploration.lab.ejbspring.transfer.service.spring-ctx.xml

If more than one bean of MoneyTransferService type were created, the exact one bean could be distinguished using @Qualifier. The initialBalance property is defined in com.softexploration.lab.ejbspring.transfer.service.spring/src/main/resources/META-INF/app.properties file and represents initial account balance.

<!-- […] -->
<bean id="app.context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
 <constructor-arg>
<list>
	 <value>classpath:META-INF/com.softexploration.lab.ejbspring.transfer.service.spring-ctx.xml</value>
</list>
 </constructor-arg>
</bean>
<!-- […] -->

Figure 7: com.softexploration.lab.ejbspring.transfer.facade.ejb/src/main/resources/beanRefContext.xml

<!-- […] -->
<ejb-local-ref>
	<ejb-ref-name>ejb/EJBMoneyTransferFacade</ejb-ref-name>
	<local>com.softexploration.lab.ejbspring.transfer.facade.MoneyTransferFacade</local>
</ejb-local-ref>
<!-- […] -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
	<param-name>locatorFactorySelector</param-name>
	<param-value>classpath:beanRefContext.xml</param-value>
</context-param>
<context-param>
	<param-name>parentContextKey</param-name>
	<param-value>app.context</param-value>
</context-param>
<!-- […] -->

Figure 8: com.softexploration.lab.ejbspring.transfer.webapp/src/main/webapp/WEB-INF/web.xml

// […]
@Stateless
@Local(MoneyTransferFacade.class)
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class EJBMoneyTransferFacade implements MoneyTransferFacade {

	@Autowired
	private MoneyTransferService moneyTransferService;

	public MoneyTransferResponse transfer(MoneyTransferRequest request) {
		return moneyTransferService.transfer(request);
	}

	public Double getBalance() {
		return moneyTransferService.getBalance();
	}
}

Figure 9: com.softexploration.lab.ejbspring.transfer.facade.ejb.EJBMoneyTransferFacade

3. Accessing EJB from Spring beans

SLSB accessing general approach

Spring Framework especially supports accessing stateless type of EJB. The obtained EJB is here treated like an ordinary Spring bean (type: org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean). There needs to be specified the JNDI name of the EJB and the business interface in Spring bean definition. Additionally, when the resourceRef attribute is set to true then the mandatory JNDI prefix: java:comp/env is added automatically to the name.

<bean id="sLEJBMoneyTransferService"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
 <property name="jndiName" value="ejb/SLEJBMoneyTransferService"/>
 <property name="businessInterface" value="com.softexploration.lab.ejbspring.transfer.service.MoneyTransferService"/>
 <property name="resourceRef" value="true" />
</bean>

<bean id="spring-slejbMoneyTransferFacade" class="com.softexploration.lab.ejbspring.transfer.facade.spring.SpringMoneyTransferFacade">
		<property name="moneyTransferService" ref="sLEJBMoneyTransferService" />
</bean>

Figure 10: accessing SLSB in Spring using LocalStatelessSessionProxyFactoryBean

<jee:local-slsb id="sLEJBMoneyTransferService"
		business-interface="com.softexploration.lab.ejbspring.transfer.service.MoneyTransferService"
		jndi-name="ejb/SLEJBMoneyTransferService" resource-ref="true" />

Figure 11: accessing SLSB in Spring using spring-jee.xsd schema

The sLEJBMoneyTransferService bean definition in Figure 11 is semantically equivalent to the definition in Figure 10. Reference to sLEJBMoneyTransferService is omitted in Figure 11. The schema is defined in: http://www.springframework.org/schema/jee/spring-jee.xsd.

Remote SLSB
There is also possible to obtain remote EJB component by using SimpleRemoteStatelessSessionProxyFactoryBean instead of LocalStatelessSessionProxyFactoryBean and remote-slsb instead of local-slsb in case of spring-jee.xsd schema. The JndiEnvironment probably will be required to specify to access remote objects. More information regarding remoting EJB [4].

It can be summarized in the steps:

  1. Prepare EJB component
  2. Define an appropriate Spring bean representing EJB (point to right JNDI name, business interface, optionally set additional properties e.g. resourceRef) by specifying FactoryBean class: org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean or org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean
    or
    instead of using FactoryBean class:local-slsb or remote-slsb element from spring-jee.xsd schema
  3. Use the bean definition where needed

The other EJB accessing general approach

Accessing SFSB and Singleton Session bean in Spring is slightly different than accessing SLSB. The main difference is other FactoryBean class and no business interface declaration. There is used the JndiObjectFactoryBean class instead of LocalStatelessSessionProxyFactoryBean/ SimpleRemoteStatelessSessionProxyFactoryBean class. The JndiObjectFactoryBean does not expect business interface definition. The resourceRef property can still be specified.

<bean id="sFEJBMoneyTransferService" class="org.springframework.jndi.JndiObjectFactoryBean">
	  <property name="jndiName" value="ejb/SFEJBMoneyTransferService" />
	  <property name="resourceRef" value="true" />
</bean>

<bean id="spring-sfejbMoneyTransferFacade" class="com.softexploration.lab.ejbspring.transfer.facade.spring.SpringMoneyTransferFacade">
		<property name="moneyTransferService" ref="sFEJBMoneyTransferService" />
</bean>

Figure 12: accessing SFSB in Spring using JndiObjectFactoryBean

<jee:jndi-lookup id="singletonEJBMoneyTransferService"
		jndi-name="ejb/SingletonEJBMoneyTransferService" resource-ref="true" />

Figure 13: accessing Singleton bean in Spring using spring-jee.xsd schema

The sFEJBMoneyTransferService bean definition in Figure 13 is semantically equivalent to the definition in Figure 12. Reference to sFEJBMoneyTransferService is omitted in Figure 13. This schema is defined in: http://www.springframework.org/schema/jee/spring-jee.xsd.

Remote EJB
The JndiEnvironment probably will be required to specify to access remote objects. More information regarding remoting EJB [4].

It can be summarized in the steps:

  1. Prepare EJB component
  2. Define an appropriate Spring bean representing EJB (point to right JNDI name, optionally set additional properties e.g. resourceRef) by specifying FactoryBean class: org.springframework.jndi.JndiObjectFactoryBean
    or
    instead of using FactoryBean class: jndi-lookup element from spring-jee.xsd schema
  3. Use the bean definition where needed

Simple Enterprise Application overview

There are considered following cases:

  1. Spring Component (singleton) refers to Stateless Session Bean
  2. Spring Component (singleton) refers to Stateful Session Bean
  3. Spring Component (singleton) refers to Singleton Session Bean

Their dependencies are presented in Figure 16.

// […]
@Local(MoneyTransferService.class)
@Stateless(name = "SLEJBMoneyTransferService", mappedName = "ejb/SLEJBMoneyTransferService")
public class SLEJBMoneyTransferService extends BaseMoneyTransferService {

	@Override
	@Resource(name = "initialBalance")
	public void setBalance(Double balance) {
		super.setBalance(balance);
	}
}

Figure 14: com.softexploration.lab.ejbspring.transfer.service.ejb.impl.SLEJBMoneyTransferService

Figure 14 presents MoneyTransferService implementation provided in SLEJBMoneyTransferService. The stateful SFEJBMoneyTransferService and singleton SingletonEJBMoneyTransferService implementations are analogous to the stateless and are not here covered. The initial available balance is defined in environment entries in the com.softexploration.lab.ejbspring.transfer.service.ejb/src/main/resources/META-INF/ejb-jar.xml file.

// […]
@Component
public class SpringMoneyTransferFacade implements MoneyTransferFacade {

	private MoneyTransferService moneyTransferService;

	public void setMoneyTransferService(MoneyTransferService moneyTransferService) {
		this.moneyTransferService = moneyTransferService;
	}

	public MoneyTransferResponse transfer(MoneyTransferRequest request) {
		return moneyTransferService.transfer(request);
	}

	public Double getBalance() {
		return moneyTransferService.getBalance();
	}
}

Figure 15: com.softexploration.lab.ejbspring.transfer.facade.spring.SpringMoneyTransferFacade

<!-- […] -->
<!-- facades -->
<bean id="spring-slejbMoneyTransferFacade"
	class="com.softexploration.lab.ejbspring.transfer.facade.spring.SpringMoneyTransferFacade">
	<property name="moneyTransferService" ref="sLEJBMoneyTransferService" />
</bean>

<bean id="spring-sfejbMoneyTransferFacade"
	class="com.softexploration.lab.ejbspring.transfer.facade.spring.SpringMoneyTransferFacade">
	<property name="moneyTransferService" ref="sFEJBMoneyTransferService" />
</bean>

<bean id="spring-singletonejbMoneyTransferFacade"
	class="com.softexploration.lab.ejbspring.transfer.facade.spring.SpringMoneyTransferFacade">
	<property name="moneyTransferService" ref="singletonEJBMoneyTransferService" />
</bean>

<!-- services -->
<jee:local-slsb id="sLEJBMoneyTransferService"
	business-interface="com.softexploration.lab.ejbspring.transfer.service.MoneyTransferService"
	jndi-name="ejb/SLEJBMoneyTransferService" resource-ref="true" />

<bean id="sFEJBMoneyTransferService" class="org.springframework.jndi.JndiObjectFactoryBean">
  <property name="jndiName" value="ejb/SFEJBMoneyTransferService" />
  <property name="resourceRef" value="true" />
</bean>

<jee:jndi-lookup id="singletonEJBMoneyTransferService"
	jndi-name="ejb/SingletonEJBMoneyTransferService" resource-ref="true" />
<!-- […] -->

Figure 16: com.softexploration.lab.ejbspring.transfer.facade.spring/src/main/resources/META-INF/com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml

There are created three SpringMoneyTransferFacade instances (Figure 16), each of them refers to other EJB service implementation.

<!-- […] -->
<import resource="classpath:META-INF/com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml" />
<!-- […] -->

Figure 17: com.softexploration.lab.ejbspring.transfer.webapp/src/main/webapp/WEB-INF/applicationContext.xml

The com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml context is included in applicationContext.xml in the web tier.

<!-- […] -->
<ejb-local-ref>
	<ejb-ref-name>ejb/SLEJBMoneyTransferService</ejb-ref-name>
	<local>com.softexploration.lab.ejbspring.transfer.service.MoneyTransferService</local>
	<ejb-link>SLEJBMoneyTransferService</ejb-link>
</ejb-local-ref>
<ejb-local-ref>
	<ejb-ref-name>ejb/SFEJBMoneyTransferService</ejb-ref-name>
	<local>com.softexploration.lab.ejbspring.transfer.service.MoneyTransferService</local>
	<ejb-link>SFEJBMoneyTransferService</ejb-link>
</ejb-local-ref>
<ejb-local-ref>
	<ejb-ref-name>ejb/SingletonEJBMoneyTransferService</ejb-ref-name>
	<local>com.softexploration.lab.ejbspring.transfer.service.MoneyTransferService</local>
	<ejb-link>SingletonEJBMoneyTransferService</ejb-link>
</ejb-local-ref>
<!-- […] -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<!-- […] -->

Figure 18: com.softexploration.lab.ejbspring.transfer.webapp/src/main/webapp/WEB-INF/web.xml

4. Troubleshooting

The official reference tells about possible problems regarding JNDI lookup [3]. The main problem is when Spring bean instantiation takes places before loading target EJB environment. When such bean is created the expected JNDI name may be not available. This leads to exception at runtime. There are some clues to overcome this behavior:

  1. Lazy initialization of Spring beans (lazy-init=”true”)
  2. Set the lookup-home-on-startup property to false in Spring bean definition

The configuration of the example application does not contain additional preventive declarations. The application was stable during tests on both Weblogic and TomEE+ application servers. Problems occurred when spring context definitions (applicationContext.xml and beanRefContext.xml) were merged into one.

Integrating spring application context

The example application contains two spring application contexts:

  1. com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml included in applicationContext.xml
  2. com.softexploration.lab.ejbspring.transfer.service.spring-ctx.xml included in beanRefContext.xml

To have only one context, the com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml should be moved from applicationContext.xml to beanRefContext.xml. It is crucial to remain the context in beanRefContext.xml because of SpringBeanAutowiringInterceptor requirements.

Moving spring application context

Here are  steps to move spring application context from com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml to beanRefContext.xml

  1. Remove import of classpath:META-INF/com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml from applicationContext.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
    
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    </beans>
    

    Figure 19: com.softexploration.lab.ejbspring.transfer.webapp/src/main/webapp/WEB-INF/applicationContext.xml

  2. Add classpath:META-INF/com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml to beanRefContext.xml
    <!-- […] -->
    <bean id="app.context"
    		class="org.springframework.context.support.ClassPathXmlApplicationContext">
     <constructor-arg>
     <list>
      <value>classpath:META-INF/com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml</value>
      <value>classpath:META-INF/com.softexploration.lab.ejbspring.transfer.service.spring-ctx.xml</value>
     </list>
     </constructor-arg>
    </bean>
    <!-- […] -->
    

    Figure 20: com.softexploration.lab.ejbspring.transfer.facade.ejb/src/main/resources/beanRefContext.xml

  3. Set lazy beans instantiation in com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml configuration.
    <beans xmlns="http://www.springframework.org/schema/beans"
    <!-- […] -->
    default-lazy-init="true">
    <!-- […] -->
    

    Figure 21: com.softexploration.lab.ejbspring.transfer.facade.spring/src/main/resources/META-INF/com.softexploration.lab.ejbspring.transfer.facade.spring-ctx.xml

When the third step is skipped then the javax.naming.NameNotFoundException is thrown at runtime. A stack trace from Weblogic is presented in Figure 22. A behavior on TomEE+ is very similar. 

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sLEJBMoneyTransferService': Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Unable to resolve 'ejb.SLEJBMoneyTransferService'. Resolved 'ejb'; remaining name 'SLEJBMoneyTransferService'
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1488)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
[…]
Caused by: javax.naming.NameNotFoundException: Unable to resolve 'ejb.SLEJBMoneyTransferService'. Resolved 'ejb'; remaining name 'SLEJBMoneyTransferService'
	at weblogic.jndi.internal.BasicNamingNode.newNameNotFoundException(BasicNamingNode.java:1180)
	at weblogic.jndi.internal.BasicNamingNode.lookupHere(BasicNamingNode.java:270)
	at weblogic.jndi.internal.ServerNamingNode.lookupHere(ServerNamingNode.java:187)
[…]

Figure 22: Stack trace from facade=ejb-spring invocation on Weblogic

5. Summary

Going through this post by examples we can conclude that integration of EJB components and Spring beans can be implemented in a clear and consistent way. Sometimes problems may occur when EJB environment is loaded after Spring bean creation. To prevent it, a lazy instantiation can be enabled for those beans which refer to JNDI. In the example application, a configuration change was sufficient to avoid exceptions at runtime. Mixing EJB and Spring beans should be generally used only in case of integration existing systems.

References

[1] Accessing EJBs – http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/ejb.html#ejb-access

[2] EJB 3 injection interceptor – http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/ejb.html#ejb-implementation-ejb3

[3] Accessing local SLSBs – http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/ejb.html#ejb-access-local

[4] Accessing remote SLSBs – http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/ejb.html#ejb-access-remote

Resources

[1] Simple Enterprise Application [com.softexploration.lab.ejbspring.transfer.app] | GitHub [softexploration/lab]

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>