Developing with POJOs Part 2
As well as being a highly configurable way to instantiate objects, a Spring bean factory can be configured to return a proxy instead of the original object. A proxy, which is also known as an interceptor, is an object that masquerades as the original object. It executes arbitrary code before and after invoking the original object. In an enterprise Java application, interceptors can be used for a number of purposes, including security, database connection management, and transaction management.
In this example application, we can configure the Spring bean factory to wrap TransferFacade with a proxy that manages transactions. To do that, we must define several beans, including those shown in figure 2. This diagram shows the TransferFacade bean, along with PlatformTransactionManager, TransactionInterceptor, and BeanNameAutoProxyCreator, the Spring classes that make TransferFacade transactional.
Figure 2 The Spring bean definitions required to make TransferFacade transactional
The BeanNameAutoProxyCreator bean wraps TransferFacade with a TransactionInterceptor, which manages transactions using the PlatformTransactionManager. The PlatformTransactionManager in this example is implemented by the HibernateTransactionManager class, which uses the Hibernate Transaction interface to begin, commit, and roll back transactions. Listing 1 shows an excerpt from the XML configuration file that defines these beans.
Listing 1 Configuring Spring transaction management
Let's take a closer look at this listing. The following numbered list refers to the bullet points in Listing 1.
- This defines a bean called TransferFacade, which is implemented by the TransferFacadeImpl class.
- This defines a bean called PlatformTransactionManager, which is implemented by the HibernateTransactionManager class that manages transactions using the Hibernate API.
- This defines a bean called TransactionInterceptor, which is implemented by the TransactionInterceptor class that makes an object transactional. TransactionInterceptor intercepts calls to the object and calls a PlatformTransactionManager to begin, commit, and roll back transactions. It has a transactionManager property, which specifies which PlatformTransactionManager to use, and a transactionAttributeSource property, which specifies which methods to make transactional. In this example, all method calls are configured to be transactional.
- This defines a bean called BeanNameAutoProxyCreator, which wraps TransferFacade with TransactionInterceptor. It has an interceptorNames property, which specifies the list of interceptors to apply, and a beanNames property, which specifies the beans to wrap with interceptors.
These bean definitions arrange for the bean factory to wrap TransferFacade with TransactionInterceptor. When the presentation tier invokes what it thinks is TransferFacade, TransactionInterceptor is invoked instead. The sequence of events is shown in figure 3.
Figure 3 Using Spring interceptors to manage transactions
Let's look at the sequence of events:
- The presentation tier calls TransferFacade but the call is routed to TransactionInterceptor.
- TransactionInterceptor begins a transaction by calling PlatformTransactionManager, which begins a transaction using either the JTA provided by the application server or the transaction management API provided by the persistence framework.
- TransactionInterceptor invokes the real TransferFacadeImpl.
- The call to TransferFacadeImpl returns.
- TransactionInterceptor commits the transaction by calling PlatformTransactionManager.
- The call to TransactionInterceptor returns.
In step 5 TransactionInterceptor could also roll back the transaction if the TransferMoney service threw an exception. By default, TransactionInterceptor emulates EJBs and rolls back a transaction if a RuntimeException is thrown. However, you can write rollback rules that specify which exceptions should cause a transaction to be rolled back. Using rollback rules simplifies the application and decouples it from the transaction management APIs by eliminating code that programmatically rolls back transactions. This is one example of how the Spring framework is more flexible than an EJB container.
Another benefit of using Spring is that you can test your transactional POJOs without deploying them in the application server. Because code that uses JDO or Hibernate can also be tested within your IDE, you can often do a lot of development without ever starting up an application server. In fact, I often find that the only time I need to use one is when developing code that uses a service such as JMS that is provided by the application server. Even when working on the presentation tier I'm able to use a simpler web container such as Jetty. This is yet another example of how lightweight frameworks make your life as a developer easier.
The role of AOP in the Spring framework
The technology underlying Spring's transaction management mechanism is known as Aspect-Oriented Programming (AOP). AOP is a declarative mechanism for changing the behavior of an application without requiring any modification to the application itself. You write rules that specify new code to be executed when methods are called and, in some cases, fields are accessed or objects instantiated. In this example the BeanNameAutoProxyCreator arranged for the TransactionInterceptor to be executed whenever the TransferFacade was called without any code changes. AOP is not limited to transaction management, and in this book you will see examples of interceptors that implement security, manage database connections, and automatically retry transactions.
I'm using the Spring AOP implementation in this book for the simple reason that it provides the AOP interceptors for managing transactions, JDO, and Hibernate connections. It is important to remember that the techniques described in this book will work equally as well with other lightweight containers such as PicoContainer [PicoContainer], and other AOP mechanisms like AspectJ [Laddad 2003]. However, as of this writing, Spring provides the best implementation of the features required by enterprise applications such as the Food to Go application, which is the example application used throughout the rest of this book.
The Spring framework is one example of a growing number of technologies that are compelling alternatives to EJBs. Using Spring AOP provides the same benefits of using EJB session beans but also allows you to use POJOs for your problem domain. An EJB container provides a large number of services, including transaction management. But is it worth compromising the design of the application to take advantage of these services—especially if you can implement them using a technology such as Spring in an à la carte fashion?
Editor's Note: To complete this series go to www.developer.com/java/ejb/article.php/3594121
About the Author
Chris Richardson is a developer and architect with over 20 years of experience. His consulting company specializes in jumpstarting projects and mentoring teams. Chris has been a technical leader at Insignia, BEA, and elsewhere. He has a computer science degree from the University of Cambridge in England and lives in Oakland, CA.
About the BookPOJOs in Action
By Chris Richardson