You are on page 1of 4

Aspect-oriented programming (AOP) is a new methodology to complement traditional

object-oriented programming (OOP). The motivation of AOP is not to substitute for OOP. In
fact, AOP is often used together with OOP. In the world of OOP, applications are organized
with classes and interfaces. These elements are good for implementing the core business
requirements, but not the crosscutting concerns (i.e., the functions or requirements that span
multiple modules of an application). Crosscutting concerns are very common in enterprise
applications. The typical examples include logging, validation, and transaction management.
AOP provides another way for developers to organize their application structures. Instead
of the classes and interfaces of OOP, the main programming elements of AOP are aspects. You
may imagine that an aspect modularizes crosscutting concerns like a class modularizes states
and behaviors in OOP.

Besides the IoC container, another core module of the Spring framework is its AOP framework.
Currently, there are many AOP frameworks on the market implemented for different
purposes and based on different technologies, but only the following three open source AOP
frameworks have entered the mainstream:
• AspectJ, merged with AspectWerkz since version 5 (http://www.eclipse.org/aspectj/)
• JBoss AOP, as a subproject of the JBoss application server (http://labs.jboss.com/
jbossaop/)
• Spring AOP, as part of the Spring framework (http://www.springframework.org/)
Among them, AspectJ is the most complete and popular AOP framework in the Java
community. By comparison, Spring AOP is not a competitor of AspectJ to provide another
complete AOP implementation. Its purpose is only to provide an AOP solution that can consistently
integrate with its IoC container. In fact, Spring AOP will only handle crosscutting
concerns for the beans declared in its IoC container.

The core implementation technology of Spring AOP is dynamic proxy.

By definition, a crosscutting concern is a functionality that spans multiple modules of an


application. This kind of concern is often hard to modularize with the traditional objectoriented
approach. To understand crosscutting concerns, let’s start with a simple calculator
example. First, you create two interfaces, ArithmeticCalculator and UnitCalculator, for arithmetic
calculation and measurement unit conversion.

Tracing the Methods


A common requirement of most applications is to trace the activities that take place during
program execution. For the Java platform, there are several logging implementations available
for you to choose. However, if you would like your application to be independent of the logging
implementation, you can make use of the Apache Commons Logging library. It provides abstract
APIs that are implementation independent and allows you to switch between different
implementations without modifying your code.

Validating the Arguments


Now let’s consider adding a restriction to your calculators. Suppose you would like your calculators
to support positive numbers only. At the beginning of each method, you make calls to
the validate() method to check if all the arguments are positive numbers. For any negative
numbers, you throw an IllegalArgumentException.

Identifying the Problems


As you can see, the original calculator methods expand as you add more and more nonbusiness
requirements, such as logging and validation. These systemwide requirements usually
have to crosscut multiple modules, so they are called crosscutting concerns to distinguish
them from the core business requirements, which are called the core concerns of a system.
Typical crosscutting concerns within an enterprise application include logging, validation,
pooling, caching, authentication, and transaction. Figure 5-1 shows the crosscutting concerns
in your calculator application.
Figure
However, with only classes and interfaces as programming elements, the traditional
object-oriented approach cannot modularize crosscutting concerns well. Developers often
have to mix them with core concerns in the same modules. As a result, these crosscutting concerns
are spread out in different modules of an application and are thus not modularized.
There are two main problems caused by non-modularized crosscutting concerns. The
first is code tangling. Like the preceding calculator methods, each of them has to handle multiple
concerns as well as the core calculation logic at the same time. This will lead to poor code
maintainability and reusability. For instance, the preceding calculator implementations would
be hard to reuse in another application that has no logging requirement and can accept negative
numbers as operands.

Another problem caused by non-modularized crosscutting concerns is code scattering.


For the logging requirement, you have to repeat the logging statements multiple times in multiple
modules to fulfill a single requirement. Later, if the logging criteria change, you would
have to modify all of the modules. Moreover, it is also hard to ensure that the logging requirement
will be implemented consistently. If you have missed a logging statement somewhere,
the overall system logging will be inconsistent.
For all these reasons, the calculators should concentrate on the core calculation logic
only. Let’s separate the logging and validation concerns from them.

Modularizing Crosscutting Concerns with Dynamic Proxy


You can apply a design pattern called proxy to separate crosscutting concerns from core concerns.
Proxy is one of the 23 GoF (Gang of Four) object-oriented design patterns, which belong
to the “structural pattern” category.

The principle of the proxy design pattern is to wrap an object with a proxy and use this
proxy to substitute for the original object. Any calls that were made to the original object will
go through the proxy first. Figure 5-2 illustrates the general idea of the proxy design pattern.
The proxy object is responsible for deciding when and whether to forward method calls to
the original object. In the meanwhile, the proxy can also perform additional tasks around each
method call. So, the proxy would be a good place to implement the crosscutting concerns.

In Java, there are two ways to implement the proxy design pattern. The traditional one is
to write a static proxy in pure object-oriented style. Static proxy works by wrapping an object
with a dedicated proxy to performadditional tasks around each method call. The dedication
means you have to write a proxy class for each interface to be able to substitute for the original
implementation, which is very inefficient in a large application with hundreds or thousands of
components

Another method is through the dynamic proxy support offered by JDK version 1.3 or
higher. It supports creating a proxy dynamically for any object. The only restriction is that the
object must implement at least one interface, and only the calls to the methods declared in
the interfaces will go through the proxy. However, there’s another kind of proxy, CGLIB proxy,
that doesn’t have this restriction. It can handle all the methods declared in a class even if it
doesn’t implement any interface.

Dynamic proxies are implemented with the Java Reflection API, so they can be used in a
more general way than static proxies. For this reason, dynamic proxy is one of the core
technologies
used by Spring for its AOP implementation.

Modularizing Crosscutting Concerns with Classic Spring


Advices

Problem
As crosscutting concerns are often hard to modularize with the traditional object-oriented
approach, you would like to seek another approach to modularize them. Dynamic proxy is
helpful in modularizing crosscutting concerns, but it’s too demanding for an application
developer to write such low-level proxy code.

Solution
AOP defines a group of high-level concepts for application developers to express their crosscutting
concerns. First, the crosscutting action to take at a particular execution point is
encapsulated in an advice. For example, you can encapsulate the logging and validation
actions in one or more advices.

Classic Spring AOP supports four types of advices, each of which takes effect at different
times of an execution point. In the formal AOP definition, there are many types of execution
points, including method executions, constructor executions, and field accesses. However,
Spring AOP only supports method executions. So, the definition of the four classic advice
types can be narrowed down to the following:
• Before advice: Before the method execution
• After returning advice: After the method returns a result
• After throwing advice: After the method throws an exception
• Around advice: Around the method execution

When using the classic Spring AOP approach, advices are written by implementing one of
the proprietary advice interfaces.

You might also like