Sign In/My Account | View Cart  

advertisement

AddThis Social Bookmark Button

Listen Print Discuss

POJO Application Frameworks: Spring Vs. EJB 3.0
Pages: 1, 2

Declarative Services

Spring and EJB 3.0 wire runtime services (such as transaction, security, logging, messaging, and profiling services) to applications. Since those services are not directly related to the application's business logic, they are not managed by the application itself. Instead, the services are transparently applied by the service container (i.e., Spring or EJB 3.0) to the application at runtime. The developer (or administrator) configures the container and tells it exactly how/when to apply services.



EJB 3.0 configures declarative services using Java annotations, while Spring uses XML configuration files. In most cases, the EJB 3.0 annotation approach is the simpler and more elegant way for this type of services. Here is an example of applying transaction services to a POJO method in EJB 3.0.


public class Foo {
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public bar () {
      // do something ...
    }    
}

You can also declare multiple attributes for a code segment and apply multiple services. This is an example of applying both transaction and security services to a POJO in EJB 3.0.


@SecurityDomain("other")
public class Foo {
    
    @RolesAllowed({"managers"})
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public bar () {
      // do something ...
    }   
}

Using XML to specify code attributes and configure declarative services could lead to verbose and unstable configuration files. Below is an example of XML elements used to apply a very simple Hibernate transaction to the Foo.bar() method in a Spring application.


<!-- Setup the transaction interceptor -->
<bean id="foo" 
  class="org.springframework.transaction
        .interceptor.TransactionProxyFactoryBean">
    
    <property name="target">
        <bean class="Foo"/>
    </property>
    
    <property name="transactionManager">
        <ref bean="transactionManager"/>
    </property>
    
    <property name="transactionAttributeSource">
        <ref bean="attributeSource"/>
    </property>
</bean>

<!-- Setup the transaction manager for Hibernate -->
<bean id="transactionManager" 
  class="org.springframework.orm
         .hibernate.HibernateTransactionManager">
    
    <property name="sessionFactory">
        <!-- you need to setup the sessionFactory bean in 
             yet another XML element -- omitted here -->
        <ref bean="sessionFactory"/>
    </property>
</bean>

<!-- Specify which methods to apply transaction -->
<bean id="transactionAttributeSource"
  class="org.springframework.transaction
         .interceptor.NameMatchTransactionAttributeSource">
  
    <property name="properties">
        <props>
            <prop key="bar">
        </props>
    </property>
</bean>

The XML complexity would grow geometrically if you added more interceptors (e.g., security interceptors) to the same POJO. Realizing the limitations of XML-only configuration files, Spring supports using Apache Commons metadata to specify transaction attributes in the Java source code. In the latest Spring 1.2, JDK-1.5-style annotations are also supported. To use the transaction metadata, you need to change the above transactionAttributeSource bean to an AttributesTransactionAttributeSource instance and add additional wirings for the metadata interceptors.


<bean id="autoproxy"
    class="org.springframework.aop.framework.autoproxy
           .DefaultAdvisorAutoProxyCreator"/>
<bean id="transactionAttributeSource"
    class="org.springframework.transaction.interceptor
           .AttributesTransactionAttributeSource"
    autowire="constructor"/>
<bean id="transactionInterceptor"
    class="org.springframework.transaction.interceptor
           .TransactionInterceptor"
    autowire="byType"/>
<bean id="transactionAdvisor"
    class="org.springframework.transaction.interceptor
           .TransactionAttributeSourceAdvisor"
    autowire="constructor"/>
<bean id="attributes"
    class="org.springframework.metadata.commons
           .CommonsAttributes"/>

The Spring metadata simplifies the transactionAttributeSource element when you have many transactional methods. But it does not solve the fundamental problems with XML configuration files--the verbose and fragile transaction interceptor, transactionManager, and transactionAttributeSource are all still needed.

Dependency Injection

A key benefit of middleware containers is that they enable developers to build loosely coupled applications. The service client only needs to know the service interface. The container instantiates service objects from concrete implementations and make them available to clients. This allows the container to switch between alternative service implementations without changing the interface or the client-side code.

The Dependency Injection pattern is one of best ways to implement loosely coupled applications. It is much easier to use and more elegant than older approaches, such as dependency lookup via JNDI or container callbacks. Using DI, the framework acts as an object factory to build service objects and injects those service objects to application POJOs based on runtime configuration. From the application developer's point of view, the client POJO automatically obtains the correct service object when you need to use it.

Both Spring and EJB 3.0 provide extensive support for the DI pattern. But they also have some profound differences. Spring supports a general-purpose, but complex, DI API based upon XML configuration files; EJB 3.0 supports injecting most common service objects (e.g., EJBs and context objects) and any JNDI objects via simple annotations.

The EJB 3.0 DI annotations are extremely concise and easy to use. The @Resource tag injects most common service objects and JNDI objects. The following example shows how to inject the server's default DataSource object from the JNDI into a field variable in a POJO. DefaultDS is the JNDI name for the DataSource. The myDb variable is automatically assigned the correct value before its first use.


public class FooDao {

    @Resource (name="DefaultDS")
    DataSource myDb;
    
    // Use myDb to get JDBC connection to the database
}

In addition to direct field variable injection, the @Resource annotation in EJB 3.0 can also be used to inject objects via a setter method. For instance, the following example injects a session context object. The application never explicitly calls the setter method--it is invoked by the container before any other methods are called.


@Resource 
public void setSessionContext (SessionContext ctx) { 
    sessionCtx = ctx; 
} 

For more complex service objects, special injection annotations are defined. For instance, the @EJB annotation is used to inject EJB stubs and the @PersistenceContext annotation is used to inject EntityManager objects, which handle database access for EJB 3.0 entity beans. The following example shows how to inject an EntityManager object into a stateful session bean. The @PersistenceContext annotation's type attribute specifies that the injected EntityManager has an extended transaction context--it does not automatically commit with the JTA transaction manager, and hence it can be used in an application transaction that spans across multiple threads in a session.


@Stateful
public class FooBean implements Foo, Serializable {

    @PersistenceContext(
      type=PersistenceContextType.EXTENDED
    )
    protected EntityManager em;
    
    public Foo getFoo (Integer id) {
        return (Foo) em.find(Foo.class, id);
    }
}

The EJB 3.0 specification defines server resources that can be injected via annotations. But it does not support user-defined application POJOs to be injected into each other.

In Spring, you first need to define a setter method (or constructor with arguments) for the service object in your POJO. The following example shows that the POJO needs a reference to the Hibernate session factory.


public class FooDao {
    
    HibernateTemplate hibernateTemplate;
    
    public void setHibernateTemplate (HibernateTemplate ht) {
        hibernateTemplate = ht;
    }
    
    // Use hibernateTemplate to access data via Hibernate
    public Foo getFoo (Integer id) {
        return (Foo) hibernateTemplate.load (Foo.class, id);
    }
}

Then, you can specify how the container gets the service object and wire it to the POJO at runtime through a chain of XML elements. The following example shows the XML element that wires a data source to a Hibernate session factory, the session factory to a Hibernate template object, and finally, the template object to the application POJO. Part of the reason for the complexity of the Spring code is the fact that we need to inject the underlying Hibernate plumbing objects manually, where the EJB 3.0 EntityManager is automatically managed and configured by the server. But that just brings us back to the argument that Spring is not as tightly integrated with services as EJB 3.0 is.


<bean id="dataSource" 
  class="org.springframework
         .jndi.JndiObjectFactoryBean">
    <property name="jndiname">
        <value>java:comp/env/jdbc/MyDataSource</value>
    </property>
</bean>

<bean id="sessionFactory" 
  class="org.springframework.orm
         .hibernate.LocalSessionFactoryBean">
    <property name="dataSource">
        <ref bean="dataSource"/>
    </property>
</bean>

<bean id="hibernateTemplate" 
  class="org.springframework.orm
         .hibernate.HibernateTemplate">
    <property name="sessionFactory">
        <ref bean="sessionFactory"/>
    </property>    
</bean>

<bean id="fooDao" class="FooDao">
    <property name="hibernateTemplate">
        <ref bean="hibernateTemplate"/>
    </property>
</bean>

<!-- The hibernateTemplate can be injected
        into more DAO objects -->

Although the XML-based Dependency Injection syntax in Spring is complex, it is very powerful. You can inject any POJO, including the ones defined in your applications, to another POJO. If you really want to use Spring's DI capabilities in EJB 3.0 applications, you can inject a Spring bean factory into an EJB via the JNDI. In some EJB 3.0 application servers, the vendor might define extra non-standard APIs to inject arbitrary POJOs. A good example is the JBoss MicroContainer, which is even more generic than Spring, as it handles Aspect-Oriented Programming (AOP) dependencies.

Conclusions

Although Spring and EJB 3.0 both aim to provide enterprise services to loosely coupled POJOs, they use very different approaches to archive this goal. Dependency Injection is a heavily used pattern in both frameworks.

With EJB 3.0, the standards-based approach, wide use of annotations, and tight integration with the application server all result in greater vendor independence and developer productivity. With Spring, the consistent use of dependency injection and the centralized XML configuration file allow developers to construct more flexible applications and work with several application service providers at a time.

Acknowledgments

The author would like to thank Stephen Chambers, Bill Burke, and Andy Oliver for valuable comments.

Resources

Michael Juntao Yuan specializes in lightweight enterprise / web application, and end-to-end mobile application development.


Return to ONJava.com.


  • Spring and/or EJB3
    2005-07-02 21:49:36  markstg [Reply | View]

    First off, EJB 3 is a great move forward, however we have to remember its not even FINAL yet.

    Secondly, I think that EJB3 and Spring could very well be used together? I could see this as a strategy for alot of shops that still like Spring, and have management that feels more comfortable with going with "standards" (whatever that really means nowadays).

    EJB 3 Persistence will just be another supported Data Access strategy supported by Spring, as well as the EJB 3 Session Bean model might be used in favor of Spring-managed business services.
    However, the IoC container provided by Spring is much more advanced than the very simple DI provided by EJB3. So for managing fine-grained objects, Spring is a clear winner in that space.
    So DI for things like lists, maps, etc. are not supported in EJB3 (from what I can tell).

    Spring's XML configuration is pretty sensible and its getting less verbose in the coming releases. Again, the Spring examples are not using the new shorthand XML notations.

    In my personal opinion, Spring really was providing for the gaps in the EJB 2.x model... EJB3 will be loads better, EJB 3 persistence great... EJB3 Session Beans.. ok whatever, not really providing anything new there in my opinion.
    I still alot of benefits to using Spring for an overall application framework, versus EJB3.
    • Spring and/or EJB3
      2005-07-03 22:39:02  MichaelYuan [Reply | View]

      Hmm, just a quick point -- EJB 3 and Spring both provide easy-to-use APIs on top of existing persistence solutions (Hibernate, Toplink, JDBC etc.) I do not think it is sensible to use EJB 3 as a persistence plug-in for Spring -- it forces two layers of abstraction and defeats the whole "standard" advantage of EJB 3.

      Of course, if you love Spring XML and have to tie your application architecture to Spring DI. Then, you should just use Spring and ignore EJB 3 altogether. :)
      • Spring and/or EJB3
        2006-10-05 11:27:24  mrpantsuit [Reply | View]

        Tying app architecture to Spring DI is impossible. The principal philosophy of Spring is loose coupling (the opposite of “tying”). Have you ever seen a bean in a Spring-based app? They have no Spring classes whatsoever. They merely have properties whose types are app interfaces. These beans have no knowledge the outside world beyond the interfaces of the app services they require.

        When making statements about “tying”, please stick to the aspects of Spring where this can actually occur: programmatic transaction management; use of Spring DAO templates and supports, etc. Also, remember that these are aspects purely optional, as is most everything in Spring.

        Also, Spring XML config looks nice and complicated in your examples, but remember that most of those XML stanzas will occur only once (transaction manager definition, etc.). The overwhelming majority of XML stanzas that developers will add to a Spring XML config are stupidly simple:

        <bean id="myService" class="mypackage.MyServiceImpl">
        <property name="anotherService" ref="anotherService"/>
        <property name="yetAnotherService" ref="yetAnotherService"/>
        </bean>

        I also agree with the other posters that annotations in a bean is a half-baked way of accomplishing DI. Once you add an EJB3 specific annotation to your POJO, it’s not really a POJO anymore, is it? I don’t know enough about it, but why didn’t they design EJB3 similar to Spring. Couldn’t they have come up with a solution that included the flexabillity, lightness, and non-intrusive nature of Spring with the scalability and distributability (not a word) of EJB3?
  • Misses the mark on Spring
    2005-07-02 18:09:57  RHassel [Reply | View]

    Spring's independence from the application server is a benefit, not a liability. Our web GUI runs in an application server, sure. But what about console utilities, automated unit tests, installation components, etc. that need access to the persistence layer and business service objects, too? App servers are not the right tool for every job. Fortunately, Spring lets me run inside or outside of a J2EE container--it's all a matter of runtime configuration.

    Also, the author overplays the "vendor lock-in" myth. The whole point of leveraging POJOs and DI is to avoid API coupling. Not a single one of my business service classes imports a Spring package. And yet, they reap the benefits of transaction management, persistence session management, configuration setting injection and more through Spring.
    • Misses the mark on Spring
      2005-07-03 22:49:17  MichaelYuan [Reply | View]

      Like I said, if you need to assemble your own app services, then Spring is a better choice, as each EJB 3 implementation is optimized for a special app server for better performance and user experience. But I disagree that unit testing is an advantage for Spring -- the new generation of lightweight EJB 3 containers makes in-container testing easier (and of course more accurate) than using mocks -- give it a try!

      In the case of your Spring application, yes, you have managed to create Spring-independent "business service" classes (IMHO, EJB 3 session bean POJOs are a lot simpler). But I am sure your application as a whole still has various dependencies on Spring (XML and helper classes). You might be well justified to have faith in Spring vendor. But I am also right in claiming that Spring causes "vendor lock-in". :)
      • Misses the mark on Spring
        2006-10-05 11:37:52  mrpantsuit [Reply | View]

        The whole point of unit testing is to test a single "unit", not "this unit + that unit". The need to test in a container is an indication of a flawed architecture.

        Mock testing w/ EasyMock is...well...easy.

        The only difference between a Spring bean and an EJB3 EJB is the addition of EJBE annotations. How does adding something make it simpler?

        I would recommend Spring2/Hibernate or Spring2/JPA for most apps and reserve EJB3 for very complex apps requiring vast scalability and distribution.
  • Bill Siggelkow photo A bit on the diagonal ...
    2005-06-30 12:57:02  Bill Siggelkow | O'Reilly Author [Reply | View]

    My gut feel is that this article is somewhat slanted. It paints Spring as a framework that is relatively closed and complex. Struts is proprietary and has managed to enjoy a modicum of success. Likewise, in my opinion this article downplays several strengths of Spring that, from a purely pragmatic standpoint, are quite important:


    • Spring is available now as a mature framework that can run without an application server, if desired.
    • Spring will run just fine on JDK 1.4.2. While I'd love to be developing with 1.5, I would bet that most corporate IT shops are not ready to make the jump.
      <lil>Spring's object factory (bean wiring) is not complex; it is robust. Any reasonably intelligent developer can understand the basics of DI just by looking at the file. After all, how hard is it to interpret this:<br/>
      <property name="greeting" value="Hello World"/>
    • Spring's DI capability is general-purpose and broad; from your article it seems that the EJB 3.0 capability is limited to managed objects.
    • Spring makes testing easier. It is laffable that you describe in-container testing as "easier".
    • Spring offers choice; this is an advantage that should not be discounted.
    <br/>
    I believe that the Java community would be better served by a discussion that focuses on the appropriateness of different frameworks. EJB 3.0 and Spring, are without a doubt both excellent frameworks for J2EE. Developers and architects want to know how well these different frameworks meet their needs. The answers to those questions are the ones that will really help.
  • A bit on the diagonal ...
    2005-06-30 21:53:49  MichaelYuan [Reply | View]


    Sorry if you feel that the article is biased against Spring. But actually, I did discuss Spring's advantage over EJB 3.0. For instance, it is more flexible, has generic DI and the XML config format does have advantages in some situations ...

    Furthermore, I believe EJB 3.0 is greatly indebted to open source frameworks like Spring and Hibernate -- they pioneered the key concepts in EJB 3.0.

    However, I also believe that EJB 3.0 learned the lessons from Spring and Hibernate so well that, in most cases, EJB 3.0 addresses what most developers need with a standard API. I guess that is cause of the perception that the article is "biased". But believe me, I did not intend to talk down upon Spring.

    As for "in container testing", I do believe it is better than mocking -- if the container is lightweight and small. But obviously, this is subject to debate. :)
  • Another benefit of EJB 3.0
    2005-06-30 10:15:03  whartung [Reply | View]

    You missed a major benefit that EJB 3.0 has over a Spring based solution.

    EJB 2.0

    Bascially, the 3.0 containers have to support the 2.0 beans as well. This will complicate the container, and make them larger by having to be backward compatible, but it also means that an EJB 2.0 project can incrementally start using the EJB 3.0 beans, without having to replumb everything else.

    Now you can certainly embed Spring into an existing solution, but then you have to basically maintain both configurations as you move forward.

    With 3.0, your old code should pretty much remain untouched, yet still easily be able to reference new code through JNDI et al.

    So, on top of the vendor independence, you get the backward compatability as well.
    • Another benefit of EJB 3.0
      2005-06-30 22:00:02  MichaelYuan [Reply | View]


      Thanks for your comments. I did overlook this point. However, Spring does work with EJB 2.1 as well. It is different than the seamless backward compatibility EJB 3.0 provides. But you can use Spring on top of you old EJB 2.1 applications.
  • Wrong
    2005-06-30 08:04:59  yetanotherchristypedude [Reply | View]

    The author writes:

    So if you need to switch the persistence service provider (e.g., change from JDBC to Hibernate) for a Spring application, you will need to refactor your application code to use the new helper classes.

    This could be more wrong, but I'm not sure how! We use Spring, and changed from JDBC to iBATIS without changing a single line of application code. We did have to change two lines of XML, though.
    • Wrong
      2005-06-30 09:30:07  MichaelYuan [Reply | View]


      Thank you for sharing your experience. I believe in a generic Spring application, you do need to change the helper classes to switch from one persistence provider to another. I am sure there are cases where you can design application so that the switch only requires minimal effort. But the article is talking about the generic picture.

      I ran the article through several Spring developers I knew. They did not dispute that point. So, I guess they had more or less the same experience I had. But, I'd like to be corrected if I am overstating the problem. So, I appreciate your input.
  • Will EJB 3.0 run in any Servlet Container?
    2005-06-30 06:22:59  Julian-Garcia [Reply | View]

    Will EJB 3.0 run in any Servlet Container? Spring does.
    • Will EJB 3.0 run in any Servlet Container?
      2005-08-13 10:20:54  alexisk [Reply | View]

      Yes, it will (it should)...
      EJB 3.0 is embeddable like it is said in the specifications! So you can embed EJB in Tomcat...


      One thing: EJB 3.0 and Spring have really different usages and they are more complementary than concurrent:

      EJB allow with RMI to send object over the network, does spring has this feature? I don't believe, the fact is the you fight on some fonctionnalities which are provided by both, but EBJ is in my mind a very different thing than Spring!!
      • Will EJB 3.0 run in any Servlet Container?
        2007-05-17 08:12:43  reardon [Reply | View]

        In fact Spring does have remoting with RMI as well as SOAP, Hessian and Burlap.
    • Will EJB 3.0 run in any Servlet Container?
      2005-06-30 09:18:10  MichaelYuan [Reply | View]


      As I discussed the in article, the key difference between EJB 3.0 and Spring is that the vendor integrates the stack for you in EJB 3.0 while Spring gives you more flexibility in assembling your own stack -- at a cost in complexity, of course.

      So, to answer your question, EJB 3.0 will run on any servlet container the vendor supports, which will eventually include all servlet containers but we are not there yet.

      On the other hand, there is an effort at JBoss to develop an embedded version of EJB 3.0. It will run in generic J2SE environment and hence will run in any J2SE servlet container if you choose to do so.

      Also, just to be picky: Neither Spring nor EJB 3.0 will run on *any* servlet container. OSGi has a servlet container for J2ME devices. I do not think either will run on that anytime soon. ;)