Blogger templates

Your Ad Here

Video

Blogroll

Blogger news

Implementing EJBs


If you choose to use EJB, Spring can provide important benefits in both EJB implementation and client-side access to EJBs.
It's now widely regarded as a best practice to refactor business logic into POJOs behind EJB facades. (Among other things, this makes it much easier to unit test business logic, as EJBs depend heavily on the container and are hard to test in isolation.) Spring provides convenient superclasses for session beans and message driven beans that make this very easy, by automatically loading a BeanFactory based on an XML document included in the EJB Jar file.
This means that a stateless session EJB might obtain and use a collaborator like this:
import org.springframework.ejb.support.AbstractStatelessSessionBean;

public class MyEJB extends AbstractStatelessSessionBean
implements MyBusinessInterface {
       private MyPOJO myPOJO;

       protected void onEjbCreate() {
              this.myPOJO = getBeanFactory().getBean("myPOJO");
       }

       public void myBusinessMethod() {
              this.myPOJO.invokeMethod();
       }
}
Assuming that MyPOJO is an interface, the implementing class - and any configuration it requires, such as primitive properties and further collaborators - is hidden in the XML bean factory definition.
We tell Spring where to load the XML document via an environment variable definition named ejb/BeanFactoryPath in the standard ejb-jar.xml deployment descriptor, as follows:
<session>
    <ejb-name>myComponent</ejb-name>
    <local-home>com.test.ejb.myEjbBeanLocalHome</local-home>
    <local>com.mycom.MyComponentLocal</local>
    <ejb-class>com.mycom.MyComponentEJB</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>/myComponent-ejb-beans.xml</env-entry-value>
   </env-entry>
</session>
The myComponent-ejb-beans.xml file will be loaded from the classpath: in this case, in the root of the EJB Jar file. Each EJB can specify its own XML document, so this mechanism can be used multiple times per EJB Jar file.
The Spring superclasses implement EJB lifecycle methods such as setSessionContext() and ejbCreate(), leaving the application developer to optionally implement the Spring onEjbCreate() method.
When EJB 3.0 is available in public draft, we will offer support for the use of the Spring IoC container to provide richer Dependency Injection semantics in that environment. We will also integrate the JSR-220 O/R mapping API with Spring as a supported data access API.
Using EJBs
Spring also makes it much easier to use, as well as implement EJBs. 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:
  • Typically code using EJBs depends on Service Locator or Business Delegate singletons, making it hard to test.
  • 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.
  • 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.
For these and other reasons, traditional EJB access, as demonstrated in applications such as the Sun Adventure Builder and OTN J2EE Virtual Shopping Mall, can reduce productivity and result in significant complexity.
Spring steps beyond this by introducing codeless business delegates. With Spring you'll never need to write another Service Locator, another JNDI lookup, or duplicate methods in a hand-coded Business Delegate unless you're adding real value.
For example, imagine that we have a web controller that uses 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. (One of the main reasons to do this is to ensure that synchronization between method signatures in local interface and bean implementation class is automatic.) Let's call this business methods interface MyComponent. Of course we'll also need to implement the local home interface and provide a bean implementation class that implements SessionBean and the MyComponent business methods interface.
With Spring EJB access, 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 MyComponent on our controller. This will save the reference as an instance variable like this:
private MyComponent myComponent;

public void setMyComponent(MyComponent myComponent) {
      this.myComponent = myComponent;
}
We can subsequently use this instance variable in any business method.
Spring does the rest of the work automatically, via XML bean definition entries like this. LocalStatelessSessionProxyFactoryBean is a generic factory bean that can be used for any EJB. The object it creates can be cast by Spring to the MyComponent type automatically.
<bean id="myComponent"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
      <property name="jndiName" value="myComponent" />
      <property name="businessInterface" value="com.mycom.MyComponent" />
</bean>

<bean id="myController" class = "com.mycom.myController">
       <property name="myComponent" ref="myComponent"/> </bean>                                                                                                                    
There's a lot of magic 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 "myComponent" 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 normally only a single JNDI lookup. (There is also support for retry on failure, so an EJB redeployment won't cause the client to fail.) Each time the EJB is invoked, the proxy invokes the create() method on the local EJB and invokes the corresponding business method on the EJB.
The myController bean definition sets the myController property of the controller class to this proxy.
This EJB access mechanism delivers huge simplification of application code:
  • The web tier 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 myComponent bean definition without changing a line of Java code
  • We haven't had to write a single line of JNDI lookup or other EJB plumbing code as part of our application.
We can also apply the same approach to remote EJBs, via the similar org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean factory bean. However, it's trickier to conceal the RemoteExceptions on the business methods interface of a remote EJB. (Spring does let you do this, if you wish to provide a client-side service interface that matches the EJB remote interface but without the "throws RemoteException" clause in the method signatures.) 


Next : Testing 
 

Most Reading

Stats