You are on page 1of 11

How to use EJB with Spring framework?

Enterprise Java Beans (EJB) implementation in Spring’s


environment API that are provided by the Spring framework with set
of classes and interfaces are found in the packages:

org.springframework.ejb.support

org.springframework.ejb.access

This package contains the base supporting classes for creating


an enterprise bean. Consider in order to create stateless session
bean we can make use of the class 'AbstractStatelessSessionBean'.
Similarly,the classes AbstractStatefulSessionBean and
AbstractJmsMessageDrivenBean correspond to Stateful Session
Bean and Message Driven Bean respectively.

These classes generally form the Facade for the clients. It means
that the core logic for doing an operation will be implementated as
a POJO (Plain Old Java Object) and the Enterprise Beans merely
serve as a facade and delegate the control to POJOs. One of the
major disadvantages that the developers would have felt while
using the Enterprise Bean running in a EJB Container is that it will
be harder for them to perform unit testing. With the use of Spring’s
approach, unit testing becomes much simplier since the
implementation classes are POJO.
A super-class for all Enterprise Beans is : the
AbstractEnterpriseBean that contains a method for loading beans
from the Application context that use the
ContextJndiBeanFactoryLocator and it is going to create a
BeanFactory object by collecting the location from one or more
classpath address as specified by the default environment variable,
Consider the following default Bean Factory locating strategy,
<session>

<env-entry>
<env-entry-name>ejb/BeanFactoryPath</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>applicationContext.xml</env-entry-value>
</env-entry>

...

</session>
We can see from the above code snippet that the default
environment variable corresponds to the default bean factory
locator key and in our case it happens to be 'ejb/BeanFactoryPath'.
This always can be overridden programmatically by calling the
method as follows,

String beanFactoryLocatorKey =
"applicationSpecificBeanFactoryLocator";
bean.setBeanFactoryLocatorKey(beanFactoryLocatorKey);
The default BeanFactory Locator is
the ContextJndiBeanFactoryLocator and this can also be overridden
programmatically by calling the following method,

BeanFactoryLocator myBeanFactoryLocator = ...;


Bean.setBeanFactoryLocator(myBeanFactoryLocator);
2.2) Accessing Enterprise Beans
The mode of accessing a Stateful Session Bean is different from the way a
Stateless Session Bean is accessed. Let us look into the support for
accessing a Stateless Session Bean (both local and remote).
For accessing a Local Stateless Session Bean, we need to use the
supporting class LocalStatelessSessionProxyFactoryBean. The
configuration for accessing a local stateless session bean is as
follows,

<bean id="sajjadBean">

<property name="jndiName">
<value>ejb/myBeanService</value>
</property>

<property name="businessInterface">
<value>MyComponentService</value>
</property>

</bean>
There are two properties for configuring a local stateless session bean
using Proxy mechanism. The first property 'jndiName' is the Jndi name of the
bean which can be used by the Jndi Bean Factory object to perform lookup
operation. The second property 'businessInterface' defines the business
interface for which the implementation will be generated by the Spring
container and delegation will be made to the actual implementation.
Similarly, for accessing the Remote Stateless Session Bean, the
class SimpleRemoteStatelessSessionProxyFactoryBean has to be used
instead of LocalStatelessSessionProxyFactoryBean. The
properties 'jndiName' and 'businessInterface' will still be applicable.
There is no direct support in Spring for accessing the Stateful Session Beans
using Proxy mechanisms. However, a convenient way is provided in the form
of JndiObjectFactoryBean.
Let us consider the following configuration,

<bean id="myServiceHome">

<property name="jndiName">
<value>ejb/myService</value>
</property>

</bean>
In the above Xml snippet, we have configured an instance of a EJB
Home interfacewith the help of JndiObjectFactoryBean. In a
traditional EJB Applicaition, we have to manually do a JNDI lookup
using the InitialContext to get a reference to the EJB Home object.
But in Spring, the lookup operation is made easy merely by putting
some configuration information,
We would have to use the following approach to get a reference to
the Stateful Session Bean,

ApplicationContext context = .... ; // Initialize the Application


context.
MyServiceHome myServiceHome =
(MyServiceHome)context.getBean("myServiceHome");

MyService myService = myServiceHome.create();


// Perform the required business logic using this bean.
.
.
.
3) Creating a Stateless Session Bean
In this section, let us see an example for creating a simple Stateless
Session using the supporting Spring APIs. One of the major goals of
Spring is to facilitate unit testing in a much simpler way, which
means that the implementation classes should not depend on the
third-party library classes. Let us develop a Hello Service
Application.

3.1) The Business Interface


Let us define the business interface for our Application as follows,
HelloService.java

package javabeat.net.articles.spring.ejb.integration.stateless;

public interface HelloService {

public String hello();


}
The interface has a single method hello() which is intended to be
given implementation by some classes.

3.2) The Implementation class


HelloServiceImpl.java

package javabeat.net.articles.spring.ejb.integration.stateless;

public class HelloServiceImpl implements HelloService{

public String hello() {


return "Hello";
}

}
The above class provides a simple implementation for the business
interface HelloService. The implementation merely returns the
string “Hello”. Note that a real implementation may contain much
sophisticated logic by maintaining transaction, accessing the
database, etc.. It is evident that the above business
interface follows the POJO standard which means that it will be
easier to perform Unit Testing in isolation by providing Mock
Implementation.

3.3) The EJB Local Object


HelloServiceLocal.java

package javabeat.net.articles.spring.ejb.integration.stateless;

import javax.ejb.EJBLocalObject;
public interface HelloServiceLocal extends HelloService,
EJBLocalObject{

}
Let us define a Local interface by extending the EJBLocalObject.
Note that this interface also extends our business
interface HelloService. This is the client-facing interface meaning
that the client will invoke all the business operation through this
interface.

3.4) The EJB Home Object


Home interfaces follow Factory patterns to return either Local or
Remote objects. Usually clients will obtain a reference to the Home
interface through JNDI, then will create the Local (or Remote)
interface by using one of the create methods.
HelloServiceHome.java

package javabeat.net.articles.spring.ejb.integration.stateless;

import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;

public interface HelloServiceHome extends EJBLocalHome {

public HelloServiceLocal create() throws CreateException;

}
The above Home interface contains a create() method that returns
a HelloServiceLocal object.

3.5) The Hello Service EJB


HelloServiceEjb.java

package javabeat.net.articles.spring.ejb.integration.stateless;
import javax.ejb.CreateException;
import org.springframework.beans.factory.BeanFactory;
import
org.springframework.ejb.support.AbstractStatelessSessionBean;

public class HelloServiceEjb extends AbstractStatelessSessionBean


implements HelloService{

private HelloService helloService;

protected void onEjbCreate() throws CreateException {


BeanFactory beanFactory = getBeanFactory();
helloService =
(HelloService)beanFactory.getBean("helloService");
}

public String hello() {


return helloService.hello();
}
}
This is the real EJB Component that needs to be deployed to the
Server. Note that this class extends
the AbstractStatelessSessionBean so that it contains the
default Bean Factory Locator and some other stuffs. The EJB
Components developed through Spring’s style will merely serve as a
facade and the original implementation will be delegated to the
POJO Business Implementation class.
In the above case, even though we have a method
called hello() (this method must be defined since
the HelloServiceEjb is implementing the HelloService interface), the
implementation simply delegates the control
to HelloServiceImpl.hello(). One important point to be mentioned
here is the need for instantiation the HelloServiceobject. The default
Bean Factory object (Jndi Bean Factory Locator) is referenced and
an instance of the implementation class is acquired by calling
the getBean() method.

Recommended from our users: Dynamic Network Monitoring from


WhatsUp Gold from IPSwitch. Free Download
3.6) Bean Configuration file
spring-stateless-ejb.xml

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<bean id="helloService"
/>

</beans>
The preceding HelloEjbComponent instantiates an implementation
of HelloService through the identifier “helloService”. This identifier
should match the one that is defined in the configuration file.

3.7) Deployment Descriptor


ejb-jar.xml

<ejb-jar>

...

<session>
<ejb-name>HelloServiceEjb</ejb-name>
<local-home>
javabeat.net.articles.spring.ejb.integration.stateless.HelloServiceHo
me
</local-home>
<local>

javabeat.net.articles.spring.ejb.integration.stateless.HelloServiceLoc
al
</local>
<ejb-class>

javabeat.net.articles.spring.ejb.integration.stateless.HelloServiceEjb
</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>

<env-entry>
<env-entry-name>ejb/BeanFactoryPath</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>spring-stateless-ejb</env-entry-value>
</env-entry>
</session>

...

</ejb-jar>
The above deployment descriptor is similar to a traditional
deployment descriptor. One thing to note is the environmental
entries, that contains a key called 'ejb/BeanFactoryPath' which
contains the path to the configuration file. As mentioned in the
preceding section, the default Bean Factory Locator key
is 'ejb/BeanFactoryPath' and this can always be overridden by
specifying the property beanFactoryLocatorKey.

3.8) The Client’s Configuration file


client-spring-stateless-ejb

<beans>

<bean id="echoService">

<property name="jndiName">
<value>java:comp/env/helloService</value>
</property>
<property name="businessInterface">

<value>javabeat.net.articles.spring.ejb.integration.stateless.HelloSe
rvice</value>
</property>
</bean>

</beans>
The client accessing an Enterprise Bean can be a standalone
Remote client, or a Servlet or even can be another Enterprise Bean.
In all these cases, the client must be aware of the factors like
locating the Bean when given a Jndi name and to get a appropriate
reference to the business interface.
In the above configuration file, the property 'jndiName' is used to
locate the Enterprise Bean object. The business interface
is HelloService which means a proxy object
for HelloService interface will be returned simply because we have
configured the bean to use LocalStatelessSessionProxyFactoryBean.

4) Conclusion
A major drawback in developing a J2EE Application that makes use
of Enterprise Java Beans for doing a business operation is the un-
necessary complications available for the clients like looking up the
Home object, creating the reference etc.., and it is impossible to do
Unit testing for the Enterprise Bean as these beans always reside
within the Container. However with Spring’s way of accessing
Enterprise Beans this has been simplified.