Added the Spring Framework reference documentation
This commit is contained in:
432
spring-framework-reference/src/ejb.xml
Normal file
432
spring-framework-reference/src/ejb.xml
Normal file
@@ -0,0 +1,432 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="ejb">
|
||||
<title>Enterprise Java Beans (EJB) integration</title>
|
||||
|
||||
<section id="ejb-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
As a lightweight container, Spring is often considered an EJB
|
||||
replacement. We do believe that for many if not most applications and use
|
||||
cases, Spring as a container, combined with its rich supporting
|
||||
functionality in the area of transactions, ORM and JDBC access, is a better
|
||||
choice than implementing equivalent functionality via an EJB container and
|
||||
EJBs.
|
||||
</para>
|
||||
<para>
|
||||
However, it is important to note that using Spring does not prevent
|
||||
you from using EJBs. In fact, Spring makes it much easier to access EJBs and
|
||||
implement EJBs and functionality within them. Additionally, using Spring to
|
||||
access services provided by EJBs allows the implementation of those services
|
||||
to later transparently be switched between local EJB, remote EJB, or POJO
|
||||
(plain old Java object) variants, without the client code having to
|
||||
be changed.
|
||||
</para>
|
||||
<para>
|
||||
In this chapter, we look at how Spring can help you access and
|
||||
implement EJBs. Spring provides particular value when accessing stateless
|
||||
session beans (SLSBs), so we'll begin by discussing this.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access">
|
||||
<title>Accessing EJBs</title>
|
||||
|
||||
<section id="ejb-access-concepts">
|
||||
<title>Concepts</title>
|
||||
<para>
|
||||
To invoke a method on a local or remote stateless session bean,
|
||||
client code must normally perform a JNDI lookup to obtain the (local or
|
||||
remote) EJB Home object, then use a 'create' method call on that object
|
||||
to obtain the actual (local or remote) EJB object. One or more methods
|
||||
are then invoked on the EJB.
|
||||
</para>
|
||||
<para>
|
||||
To avoid repeated low-level code, many EJB applications use the
|
||||
Service Locator and Business Delegate patterns. These are better than
|
||||
spraying JNDI lookups throughout client code, but their usual
|
||||
implementations have significant disadvantages. For example:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Typically code using EJBs depends on Service Locator or
|
||||
Business Delegate singletons, making it hard to test.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In the case of the Service Locator pattern used without a
|
||||
Business Delegate, application code still ends up having to invoke
|
||||
the create() method on an EJB home, and deal with the resulting
|
||||
exceptions. Thus it remains tied to the EJB API and the complexity
|
||||
of the EJB programming model.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Implementing the Business Delegate pattern typically results
|
||||
in significant code duplication, where we have to write numerous
|
||||
methods that simply call the same method on the EJB.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The Spring approach is to allow the creation and use of proxy objects,
|
||||
normally configured inside a Spring container, which act as codeless
|
||||
business delegates. You do not need to write another Service Locator, another
|
||||
JNDI lookup, or duplicate methods in a hand-coded Business Delegate unless
|
||||
you are actually adding real value in such code.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-local">
|
||||
<title>Accessing local SLSBs</title>
|
||||
<para>
|
||||
Assume that we have a web controller that needs to use a local
|
||||
EJB. We’ll follow best practice and use the EJB Business Methods
|
||||
Interface pattern, so that the EJB’s local interface extends a non
|
||||
EJB-specific business methods interface. Let’s call this business
|
||||
methods interface <classname>MyComponent</classname>.
|
||||
</para>
|
||||
<programlisting><![CDATA[public interface MyComponent {
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
One of the main reasons to use the Business Methods Interface pattern
|
||||
is to ensure that synchronization between method signatures in local
|
||||
interface and bean implementation class is automatic. Another reason is
|
||||
that it later makes it much easier for us to switch to a POJO (plain old
|
||||
Java object) implementation of the service if it makes sense to do so.
|
||||
Of course we’ll also need to implement the local home interface and
|
||||
provide an implementation class that implements <classname>SessionBean</classname>
|
||||
and the <classname>MyComponent</classname> business methods interface. Now the
|
||||
only Java coding we’ll need to do to hook up our web tier controller to the
|
||||
EJB implementation is to expose a setter method of type <classname>MyComponent</classname>
|
||||
on the controller. This will save the reference as an instance variable in the
|
||||
controller:
|
||||
</para>
|
||||
<programlisting><![CDATA[private MyComponent myComponent;
|
||||
|
||||
public void setMyComponent(MyComponent myComponent) {
|
||||
this.myComponent = myComponent;
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
We can subsequently use this instance variable in any business
|
||||
method in the controller. Now assuming we are obtaining our controller
|
||||
object out of a Spring container, we can (in the same context) configure a
|
||||
<classname>LocalStatelessSessionProxyFactoryBean</classname> instance, which
|
||||
will be the EJB proxy object. The configuration of the proxy, and setting of
|
||||
the <literal>myComponent</literal> property of the controller is done
|
||||
with a configuration entry such as:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="myComponent"
|
||||
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
|
||||
<property name="jndiName" value="ejb/myBean"/>
|
||||
<property name="businessInterface" value="com.mycom.MyComponent"/>
|
||||
</bean>
|
||||
|
||||
<bean id="myController" class="com.mycom.myController">
|
||||
<property name="myComponent" ref="myComponent"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
There’s a lot of work happening behind the scenes, courtesy of
|
||||
the Spring AOP framework, although you aren’t forced to work with AOP
|
||||
concepts to enjoy the results. The <literal>myComponent</literal> bean
|
||||
definition creates a proxy for the EJB, which implements the business
|
||||
method interface. The EJB local home is cached on startup, so there’s
|
||||
only a single JNDI lookup. Each time the EJB is invoked, the proxy
|
||||
invokes the <literal>classname</literal> method on the local EJB and
|
||||
invokes the corresponding business method on the EJB.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>myController</literal> bean definition sets the
|
||||
<literal>myComponent</literal> property of the controller class to the
|
||||
EJB proxy.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively (and preferably in case of many such proxy definitions),
|
||||
consider using the <literal><jee:local-slsb></literal>
|
||||
configuration element in Spring's "jee" namespace:
|
||||
</para>
|
||||
<programlisting><![CDATA[<jee:local-slsb id="myComponent" jndi-name="ejb/myBean"
|
||||
business-interface="com.mycom.MyComponent"/>
|
||||
|
||||
<bean id="myController" class="com.mycom.myController">
|
||||
<property name="myComponent" ref="myComponent"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
This EJB access mechanism delivers huge simplification of
|
||||
application code: the web tier code (or other EJB client code) has no
|
||||
dependence on the use of EJB. If we want to replace this EJB reference
|
||||
with a POJO or a mock object or other test stub, we could simply change
|
||||
the <literal>myComponent</literal> bean definition without changing a
|
||||
line of Java code. Additionally, we haven’t had to write a single line of
|
||||
JNDI lookup or other EJB plumbing code as part of our application.
|
||||
</para>
|
||||
<para>
|
||||
Benchmarks and experience in real applications indicate that the
|
||||
performance overhead of this approach (which involves reflective
|
||||
invocation of the target EJB) is minimal, and is typically undetectable
|
||||
in typical use. Remember that we don’t want to make fine-grained calls
|
||||
to EJBs anyway, as there’s a cost associated with the EJB infrastructure
|
||||
in the application server.
|
||||
</para>
|
||||
<para>
|
||||
There is one caveat with regards to the JNDI lookup. In a bean
|
||||
container, this class is normally best used as a singleton (there simply
|
||||
is no reason to make it a prototype). However, if that bean container
|
||||
pre-instantiates singletons (as do the various XML
|
||||
<classname>ApplicationContext</classname> variants)
|
||||
you may have a problem if the bean container is loaded before the EJB
|
||||
container loads the target EJB. That is because the JNDI lookup will be
|
||||
performed in the <literal>init()</literal> method of this class and then
|
||||
cached, but the EJB will not have been bound at the target location yet.
|
||||
The solution is to not pre-instantiate this factory object, but allow it
|
||||
to be created on first use. In the XML containers, this is controlled via
|
||||
the <literal>lazy-init</literal> attribute.
|
||||
</para>
|
||||
<para>
|
||||
Although this will not be of interest to the majority of Spring
|
||||
users, those doing programmatic AOP work with EJBs may want to look at
|
||||
<classname>LocalSlsbInvokerInterceptor</classname>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-remote">
|
||||
<title>Accessing remote SLSBs</title>
|
||||
<para>
|
||||
Accessing remote EJBs is essentially identical to accessing local
|
||||
EJBs, except that the
|
||||
<classname>SimpleRemoteStatelessSessionProxyFactoryBean</classname> or
|
||||
<literal><jee:remote-slsb></literal> configuration element is used.
|
||||
Of course, with or without Spring, remote invocation semantics apply; a
|
||||
call to a method on an object in another VM in another computer does
|
||||
sometimes have to be treated differently in terms of usage scenarios and
|
||||
failure handling.
|
||||
</para>
|
||||
<para>
|
||||
Spring's EJB client support adds one more advantage over the
|
||||
non-Spring approach. Normally it is problematic for EJB client code to
|
||||
be easily switched back and forth between calling EJBs locally or
|
||||
remotely. This is because the remote interface methods must declare that
|
||||
they throw <classname>RemoteException</classname>, and client code must deal
|
||||
with this, while the local interface methods don't. Client code
|
||||
written for local EJBs which needs to be moved to remote EJBs
|
||||
typically has to be modified to add handling for the remote exceptions,
|
||||
and client code written for remote EJBs which needs to be moved to local
|
||||
EJBs, can either stay the same but do a lot of unnecessary handling of
|
||||
remote exceptions, or needs to be modified to remove that code. With the
|
||||
Spring remote EJB proxy, you can instead not declare any thrown
|
||||
<classname>RemoteException</classname> in your Business Method Interface and
|
||||
implementing EJB code, have a remote interface which is identical except
|
||||
that it does throw <classname>RemoteException</classname>, and rely on the
|
||||
proxy to dynamically treat the two interfaces as if they were the same.
|
||||
That is, client code does not have to deal with the checked
|
||||
<classname>RemoteException</classname> class. Any actual
|
||||
<classname>RemoteException</classname> that is thrown during the EJB
|
||||
invocation will be re-thrown as the non-checked
|
||||
<classname>RemoteAccessException</classname> class, which is a subclass of
|
||||
<classname>RuntimeException</classname>. The target service can then be
|
||||
switched at will between a local EJB or remote EJB (or even plain Java
|
||||
object) implementation, without the client code knowing or caring. Of
|
||||
course, this is optional; there is nothing stopping you from declaring
|
||||
<classname>RemoteExceptions</classname> in your business interface.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-ejb2-ejb3">
|
||||
<title>Accessing EJB 2.x SLSBs versus EJB 3 SLSBs</title>
|
||||
<para>
|
||||
Accessing EJB 2.x Session Beans and EJB 3 Session Beans via Spring
|
||||
is largely transparent. Spring's EJB accessors, including the
|
||||
<literal><jee:local-slsb></literal> and <literal><jee:remote-slsb></literal>
|
||||
facilities, transparently adapt to the actual component at runtime.
|
||||
They handle a home interface if found (EJB 2.x style), or perform straight
|
||||
component invocations if no home interface is available (EJB 3 style).
|
||||
</para>
|
||||
<para>
|
||||
Note: For EJB 3 Session Beans, you could effectively use a
|
||||
<classname>JndiObjectFactoryBean</classname> / <literal><jee:jndi-lookup></literal>
|
||||
as well, since fully usable component references are exposed for plain
|
||||
JNDI lookups there. Defining explicit <literal><jee:local-slsb></literal>
|
||||
/ <literal><jee:remote-slsb></literal> lookups simply provides
|
||||
consistent and more explicit EJB access configuration.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="ejb-implementation">
|
||||
<title>Using Spring's EJB implementation support classes</title>
|
||||
|
||||
<section id="ejb-implementation-ejb2">
|
||||
<title>EJB 2.x base classes</title>
|
||||
<para>
|
||||
Spring provides convenience classes to help you implement EJBs.
|
||||
These are designed to encourage the good practice of putting business
|
||||
logic behind EJBs in POJOs, leaving EJBs responsible for transaction
|
||||
demarcation and (optionally) remoting.
|
||||
</para>
|
||||
<para>
|
||||
To implement a Stateless or Stateful session bean, or a Message Driven
|
||||
bean, you need only derive your implementation class from
|
||||
<classname>AbstractStatelessSessionBean</classname>,
|
||||
<classname>AbstractStatefulSessionBean</classname>, and
|
||||
<classname>AbstractMessageDrivenBean</classname>/<classname>AbstractJmsMessageDrivenBean</classname>,
|
||||
respectively.
|
||||
</para>
|
||||
<para>
|
||||
Consider an example Stateless Session bean which actually delegates
|
||||
the implementation to a plain java service object. We have the business interface:
|
||||
</para>
|
||||
<programlisting><![CDATA[public interface MyComponent {
|
||||
public void myMethod(...);
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>We also have the plain Java implementation object:</para>
|
||||
<programlisting><![CDATA[public class MyComponentImpl implements MyComponent {
|
||||
public String myMethod(...) {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>And finally the Stateless Session Bean itself:</para>
|
||||
<programlisting><![CDATA[public class MyFacadeEJB extends AbstractStatelessSessionBean
|
||||
implements MyFacadeLocal {
|
||||
|
||||
private MyComponent myComp;
|
||||
|
||||
/**
|
||||
* Obtain our POJO service object from the BeanFactory/ApplicationContext
|
||||
* @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate()
|
||||
*/
|
||||
protected void onEjbCreate() throws CreateException {
|
||||
myComp = (MyComponent) getBeanFactory().getBean(
|
||||
ServicesConstants.CONTEXT_MYCOMP_ID);
|
||||
}
|
||||
|
||||
// for business method, delegate to POJO service impl.
|
||||
public String myFacadeMethod(...) {
|
||||
return myComp.myMethod(...);
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
The Spring EJB support base classes will by default create and load
|
||||
a Spring IoC container as part of their lifecycle, which is then available
|
||||
to the EJB (for example, as used in the code above to obtain the POJO
|
||||
service object). The loading is done via a strategy object which is a subclass of
|
||||
<classname>BeanFactoryLocator</classname>. The actual implementation of
|
||||
<classname>BeanFactoryLocator</classname> used by default is
|
||||
<classname>ContextJndiBeanFactoryLocator</classname>, which creates the
|
||||
ApplicationContext from a resource locations specified as a JNDI
|
||||
environment variable (in the case of the EJB classes, at
|
||||
<literal>java:comp/env/ejb/BeanFactoryPath</literal>). If there is a need
|
||||
to change the BeanFactory/ApplicationContext loading strategy, the default
|
||||
<classname>BeanFactoryLocator</classname> implementation used may be overridden
|
||||
by calling the <literal>setBeanFactoryLocator()</literal> method, either
|
||||
in <literal>setSessionContext()</literal>, or in the actual constructor of
|
||||
the EJB. Please see the Javadocs for more details.
|
||||
</para>
|
||||
<para>
|
||||
As described in the Javadocs, Stateful Session beans expecting to be
|
||||
passivated and reactivated as part of their lifecycle, and which use a
|
||||
non-serializable container instance (which is the normal case) will have
|
||||
to manually call <literal>unloadBeanFactory()</literal> and
|
||||
<literal>loadBeanFactory</literal> from <literal>ejbPassivate</literal>
|
||||
and <literal>ejbActivate</literal>, respectively, to unload and reload the
|
||||
BeanFactory on passivation and activation, since it can not be saved by
|
||||
the EJB container.
|
||||
</para>
|
||||
<para>
|
||||
The default behavior of the <classname>ContextJndiBeanFactoryLocator</classname>
|
||||
classes which is to load an <classname>ApplicationContext</classname> for the
|
||||
use of the EJB is adequate for some situations. However, it is problematic when
|
||||
the <classname>ApplicationContext</classname> is loading a number
|
||||
of beans, or the initialization of those beans is time consuming or memory
|
||||
intensive (such as a Hibernate <classname>SessionFactory</classname> initialization, for
|
||||
example), since every EJB will have their own copy. In this case, the user
|
||||
may want to override the default <classname>ContextJndiBeanFactoryLocator</classname>
|
||||
usage and use another <classname>BeanFactoryLocator</classname> variant, such as the
|
||||
<classname>ContextSingletonBeanFactoryLocator</classname> which can load and use a
|
||||
shared container to be used by multiple EJBs or other clients. Doing this is relatively
|
||||
simple, by adding code similar to this to the EJB:
|
||||
</para>
|
||||
<programlisting><![CDATA[ /**
|
||||
* Override default BeanFactoryLocator implementation
|
||||
* @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
|
||||
*/
|
||||
public void setSessionContext(SessionContext sessionContext) {
|
||||
super.setSessionContext(sessionContext);
|
||||
setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
|
||||
setBeanFactoryLocatorKey(ServicesConstants.PRIMARY_CONTEXT_ID);
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
You would then need to create a bean definition file named <literal>beanRefContext.xml</literal>.
|
||||
This file defines all bean factories (usually in the form of application contexts) that may be used
|
||||
in the EJB. In many cases, this file will only contain a single bean definition such as this (where
|
||||
<literal>businessApplicationContext.xml</literal> contains the bean definitions for all business
|
||||
service POJOs):
|
||||
</para>
|
||||
<programlisting><![CDATA[<beans>
|
||||
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
|
||||
<constructor-arg value="businessApplicationContext.xml" />
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
<para>
|
||||
In the above example, the <literal>ServicesConstants.PRIMARY_CONTEXT_ID</literal> constant
|
||||
would be defined as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[public static final String ServicesConstants.PRIMARY_CONTEXT_ID = "businessBeanFactory";]]></programlisting>
|
||||
<para>
|
||||
Please see the respective Javadocs for the <classname>BeanFactoryLocator</classname> and
|
||||
<classname>ContextSingletonBeanFactoryLocator</classname> classes for more information on
|
||||
their usage.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-implementation-ejb3">
|
||||
<title>EJB 3 injection interceptor</title>
|
||||
<para>
|
||||
For EJB 3 Session Beans and Message-Driven Beans, Spring provides a convenient
|
||||
interceptor that resolves Spring 2.5's <literal>@Autowired</literal> annotation
|
||||
in the EJB component class:
|
||||
<classname>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</classname>.
|
||||
This interceptor can be applied through an <code>@Interceptors</code> annotation
|
||||
in the EJB component class, or through an <literal>interceptor-binding</literal>
|
||||
XML element in the EJB deployment descriptor.
|
||||
</para>
|
||||
<programlisting><![CDATA[@Stateless
|
||||
@Interceptors(SpringBeanAutowiringInterceptor.class)
|
||||
public class MyFacadeEJB implements MyFacadeLocal {
|
||||
|
||||
// automatically injected with a matching Spring bean
|
||||
@Autowired
|
||||
private MyComponent myComp;
|
||||
|
||||
// for business method, delegate to POJO service impl.
|
||||
public String myFacadeMethod(...) {
|
||||
return myComp.myMethod(...);
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
<classname>SpringBeanAutowiringInterceptor</classname> by default obtains target
|
||||
beans from a <classname>ContextSingletonBeanFactoryLocator</classname>, with the
|
||||
context defined in a bean definition file named <literal>beanRefContext.xml</literal>.
|
||||
By default, a single context definition is expected, which is obtained by type rather
|
||||
than by name. However, if you need to choose between multiple context definitions,
|
||||
a specific locator key is required. The locator key (i.e. the name of the context
|
||||
definition in <literal>beanRefContext.xml</literal>) can be explicitly specified
|
||||
either through overriding the <literal>getBeanFactoryLocatorKey</literal> method
|
||||
in a custom <classname>SpringBeanAutowiringInterceptor</classname> subclass.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively, consider overriding <classname>SpringBeanAutowiringInterceptor</classname>'s
|
||||
<literal>getBeanFactory</literal> method, e.g. obtaining a shared
|
||||
<interfacename>ApplicationContext</interfacename> from a custom holder class.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
Reference in New Issue
Block a user