AOP is one of the key components of Spring Framework. Object-oriented programming fails to deal with technical and functional cross-cutting concerns, such as generic functionalities that are needed in many places in our application.
The following are a few examples of cross-cutting concerns:
Logging and tracing
Transaction management
Security
Caching
Error handling
Performance monitoring
Custom business rules
Event handling
In our application, we need logging to debug or troubleshoot, so we put debug messages in every method; this is a cross-cutting concern. Similarly, we secure methods for unauthorized access.
AOP overlays a new layer onto the data-driven composition of OOP. This layer corresponds to the cross-cutting functionalities that are difficult to integrate through the OOP paradigm.
AOP is implemented with AspectJ and Spring AOP:
AspectJ: This is the original AOP technology (the first version dates from 1995) that offers a full-blown, aspect-oriented programming language and uses bytecode modification for aspect weaving.
Spring AOP: This is a Java-based AOP framework and it uses dynamic proxies for aspect weaving. This focuses on using AOP to solve enterprise problems.
The following example demonstrates a cross-cutting concern:
class Account{ private double balance; public void withdraw(double amount){ logger.debug("Withdraw –"+amount); tx.begin(); balance = this.balance-amount; accountDao.saveBalance(balance); tx.commit(); } }
The withdraw
method logs debug information, begins a transaction, performs a database transaction, and finally commits the transaction. In each method, we will introduce duplicate code for debugging and opening and committing a transaction. These are cross-cutting concerns as the conceptually duplicate code will be scattered to all modules in the application. This is bad in the sense that if we need to change any settings, we have to manually change all methods in all modules, such as instead of logger.debug
, and if we need to change the logging to logger.info
, we need to modify all methods.
Before we dig deep into AOP, let's get familiar with the terminology:
Join point: This is a well-defined point during the execution of your application. You can insert additional logic at join points.
Examples of join points are as follows:
Method invocation
Class initialization
Object initialization
Advice: This is the code that is executed at a specific join point. The three types of advice are as follows:
Pointcut: This is a collection of join points to execute an advice. A join point is a possibility of executing an advice, whereas a pointcut is a set of selected join points where actually the advice is executed.
Aspect: This defines the implementation of the cross-cutting concern. An aspect is the combination of advice and pointcuts. An application can have any number of aspects, depending on the requirement.
Weaving: This is the process of applying aspects into the code at the appropriate join points. There are three types of weaving:
Compile-time weaving
Class load-time weaving
Runtime weaving
Target: This is the object that is advised by one or more aspects.
Introduction: This is the process by which you can modify the structure of an object by introducing additional methods or fields to it. You use the introduction to make any object implement a specific interface without needing the object's class to implement that interface explicitly.
There are two types of AOP:
Static AOP
Dynamic AOP
Spring AOP is based on proxies. To know more about proxies, read about the proxy pattern or visit http://en.wikipedia.org/wiki/Proxy_pattern.
We'll display Hello World! through AOP. The following are the steps to create the hello world message:
Create an interface called
IMessageWriter
:package com.packt.aop; public interface IMessageWriter { void writeMessage(); }
Create a class called
MessageWriter
and implement theIMessageWriter
interface:package com.packt.aop; public class MessageWriter implements IMessageWriter { @Override public void writeMessage() { System.out.print("World"); } }
The join point is the invocation of the
writeMessage()
method. What we need is an around advice as we'll prependHello
beforeWorld
and append the exclamation afterWorld
to make itHello World !
. TheMethodInterceptor
interface is AOP Alliance standard interface for around interface. TheMethodInvocation
object represents the method invocation that is being advised. We'll create an advice as follows:import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class MessageDecorator implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.print("Hello "); Object retVal = invocation.proceed(); System.out.println("!"); return retVal; } }
We'll use the
ProxyFactory
class to create the proxy of the target object:import org.springframework.aop.framework.ProxyFactory; public class AOPTest { public static void main(String[] args) { MessageWriter target = new MessageWriter(); // create the proxy ProxyFactory pf = new ProxyFactory(); // Add the given AOP Alliance advice to the tail // of the advice (interceptor) chain pf.addAdvice(new MessageDecorator()); // Set the given object as target pf.setTarget(target); // Create a new proxy according to the // settings in this factory MessageWriter proxy = (MessageWriter) pf.getProxy(); // write the messages target.writeMessage(); System.out.println(""); // use the proxy proxy.writeMessage(); } }
When we run the program, the MessageDecorator
around advice is applied on the proxy object. When proxy.writeMessage
is called, the correct output is displayed.