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.

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.

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.

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.

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.

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.

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.

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.