Abstract

A rapidly growing developer community, support for various backend technologies (including JMS, JTA, JDO, Hibernate, iBATIS, and many others), and, more importantly, a non-intrusive lightweight IoC container and a built-in AOP runtime make the Spring Framework very attractive for J2EE application development. Spring-managed components (POJOs) can coexist with EJBs and allow you to use an AOP approach to deal with cross-cutting aspects of enterprise applications—starting from monitoring and auditing, caching, and application-level security, and moving through to handling application-specific business requirements.

This article guides you through several practical uses of Spring's AOP framework within a J2EE application.

Introduction

J2EE technology provides a great foundation for implementing server-side and middleware applications. J2EE containers such as BEA WebLogic Server can take care of system-level elements including application life cycle, security, transactions, remoting, and concurrency, and it can guarantee support for common services like JDBC, JMS, and JTA. However, the greatness and complexity of J2EE makes development and testing more difficult. A traditional J2EE application is usually heavily reliant on the services made available through the container's JNDI. That means a lot of direct JNDI lookups, or as a slight improvement, use of the Service Locator pattern. This architecture increases the coupling between components and makes it almost impossible to test in isolation. For an in-depth analysis of the drawbacks of this architecture you can read the book, J2EE Development without EJB, written by the authors of the Spring Framework.

With the Spring Framework you can wire business logic implemented in plain Java objects with traditional J2EE infrastructure and significantly reduce the amount of code needed for accessing J2EE components and services. On top of that you can mix traditional OO design with orthogonal AOP componentization. Later in this article I demonstrate refactoring of J2EE components to make use of Spring-managed Java objects, and then apply an AOP approach to implement new features maintaining good component separation and testability.

Compared to other AOP tools, Spring provides a limited subset of AOP features. Its goal is to have close integration between AOP implementation and the Spring IoC container to help solve common application problems. Such integration is done in a non-intrusive way, which allows you to mix Spring AOP in the same application with more expressive frameworks, including AspectJ. Spring AOP uses plain Java classes and does not require a special compilation process, control of the class loader hierarchy, or deployment configuration changes. Instead, it uses the Proxy pattern to apply advices to the target object that should be managed by the Spring IoC container.

You can choose between two types of proxies, depending on the situation.
  • The first one is based on the Java dynamic proxy, which can be applied only to interfaces; it is a standard Java feature and provides good performance.

  • The second type can be used when the target object does not implement any interface and such interfaces can't be introduced (for example, in the case of legacy code). It is based on the runtime byte code generation using the CGLIB library.

For a proxied object Spring allows you to assign specific advices using either static (method match based on the exact name or regular expression or annotation-driven) or dynamic (where matching is done in the runtime, that include cflow pointcut types) pointcut definitions, and each pointcut can be associated with one or several advices. Several advice types are supported: around, before, after returning, throws, and introduction advice. Later in this article I'll show an example of the around advice; for more details you can refer to the Spring AOP framework documentation.

As mentioned earlier, you can only advise target objects managed by the Spring IoC container. However, in J2EE applications, a component's lifecycle is managed by the application server, and, depending on the type of integration, J2EE application components can be exposed to remote or local clients using one of the common end-point types:

  • Stateless, stateful, or entity beans, local or remote (over RMI-IIOP)
  • Message-driven beans (MDB) listening on local or external JMS queues and topics or inbound JCA end-points
  • Servlets (including Struts or other end-user UI frameworks, XML-RPC, and SOAP-based interfaces)

Figure 1
Figure 1. Common end-point types

To use Spring's AOP framework on those end-points, you'll have to move all the business logic into Spring-managed beans, using server-managed components to delegate calls and optionally to define transaction demarcation and a security context. Though I'll keep transactional issues aside in this article, you can find several other articles about this in the Resources section.

I'll give you a closer look at how you can refactor a J2EE application to use Spring features. You'll use XDoclet's JavaDoc-based metadata to generate home and bean interfaces as well as EJB deployment descriptors. Complete source code for all sample classes from this article is available in the Download section below.

Pages: 1, 2, 3, 4, 5

Next Page »