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:
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:
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:
Examples of join points are as follows:
There are two types of 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:
IMessageWriter
:package com.packt.aop; public interface IMessageWriter { void writeMessage(); }
MessageWriter
and implement the IMessageWriter
interface:package com.packt.aop; public class MessageWriter implements IMessageWriter { @Override public void writeMessage() { System.out.print("World"); } }
writeMessage()
method. What we need is an around advice as we'll prepend Hello
before World
and append the exclamation after World
to make it Hello World !
. The MethodInterceptor
interface is AOP Alliance standard interface for around interface. The MethodInvocation
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; } }
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.
3.16.218.221