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
How it works?,now let's seeing a simple example:
first,define two interfaces:
package cn.cgw.aop;
public interface ArithmeticCalculator {
public double add(double a, double b);
public double sub(double a, double b);
public double mul(double a, double b);
public double div(double a, double b);
}
package cn.cgw.aop;
public interface UnitCalculator {
public double kilogramToPound(double kilogram);
public double kilometerToMile(double kilometer);
}
package cn.cgw.aop;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
public double add(double a, double b) {
double result = a + b;
System.out.println(a + " + " + b + " = " + result);
return result;
}
public double sub(double a, double b) {
double result = a - b;
System.out.println(a + " - " + b + " = " + result);
return result;
}
public double mul(double a, double b) {
double result = a * b;
System.out.println(a + " * " + b + " = " + result);
return result;
}
public double div(double a, double b) {
if (b == 0) {
throw new IllegalArgumentException("Division by zero");
}
double result = a / b;
System.out.println(a + " / " + b + " = " + result);
return result;
}
}
package cn.cgw.aop;
public class UnitCalculatorImpl implements UnitCalculator {
public double kilogramToPound(double kilogram) {
double pound = kilogram * 2.2;
System.out.println(kilogram + " kilogram = " + pound + " pound");
return pound;
}
public double kilometerToMile(double kilometer) {
double mile = kilometer * 0.62;
System.out.println(kilometer + " kilometer = " + mile + " mile");
return mile;
}
}
now,we define 4 instance for erery advice:
before advice:
public class LoggingBeforeAdvice implements MethodBeforeAdvice {
private Log log = LogFactory.getLog(this.getClass());
public void before(Method method, Object[] args, Object target)
throws Throwable {
log.info("The method:" + method.getName() + "()begin with" + Arrays.toString(args));
}
}
After returning advice:
public class LoggingAfterAdvice implements AfterReturningAdvice {
private Log log = LogFactory.getLog(this.getClass());
public void afterReturning(Object returnValue, Method method, Object[] args,
Object target) throws Throwable {
log.info("The method:" + method.getName() + "() end with " + returnValue);
}
}
After throwing advice:
public class LoggingThrowsAdvice implements ThrowsAdvice {
private Log log = LogFactory.getLog(this.getClass());
public void afterThrowing(Method method, Object[] args, Object target,
IllegalArgumentException e) throws Throwable {
log.error("Illegal argument " + Arrays.toString(args) + " for method "
+ method.getName() + "()");
}
}
Around advice:
public class LoggingAroundAdvice implements MethodInterceptor {
private Log log = LogFactory.getLog(this.getClass());
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
log.info("The method " + methodInvocation.getMethod().getName()
+ "() begins with "
+ Arrays.toString(methodInvocation.getArguments()));
try {
Object result = methodInvocation.proceed();
log.info("The method " + methodInvocation.getMethod().getName()
+ "() ends with " + result);
return result;
} catch (IllegalArgumentException e) {
log.error("Illegal argument "
+ Arrays.toString(methodInvocation.getArguments())
+ " for method " + methodInvocation.getMethod().getName()
+ "()");
throw e;
}
}
}
configuration file:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="arithmeticCalculator" class="cn.cgw.aop.ArithmeticCalculatorImpl"/> <bean id="unitCalculator" class="cn.cgw.aop.UnitCalculatorImpl"/> <!-- Advice --> <bean id="loggingBeforeAdvice" class="cn.cgw.aop.LoggingBeforeAdvice"/> <bean id="loggingAfterAdvice" class="cn.cgw.aop.LoggingAfterAdvice"/> <bean id="loggingThrowsAdvice" class="cn.cgw.aop.LoggingThrowsAdvice"/> <bean id="loggingAroundAdvice" class="cn.cgw.aop.LoggingAroundAdvice"/> <!-- AOP Proxy --> <bean id="arithmeticCalculatorProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <list> <value>cn.cgw.aop.ArithmeticCalculator</value> </list> </property> <property name="target" ref="arithmeticCalculator"/> <property name="interceptorNames"> <list> <value>loggingBeforeAdvice</value> <value>loggingAfterAdvice</value> <value>loggingThrowsAdvice</value> <!-- <value>loggingAroundAdvice</value> --> </list> </property> </bean> <bean id="unitCalculatorProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <list> <value>cn.cgw.aop.UnitCalculator</value> </list> </property> <property name="target" ref="unitCalculator"/> <property name="interceptorNames"> <list> <value>loggingBeforeAdvice</value> <value>loggingAfterAdvice</value> <!-- <value>loggingAroundAdvice</value> --> </list> </property> </bean> </beans>
finally,we write a test method:
ApplicationContext context = new ClassPathXmlApplicationContext("beans-aop.xml");
ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator)context.getBean("arithmeticCalculatorProxy");
UnitCalculator unitCalculator = (UnitCalculator)context.getBean("unitCalculatorProxy");
arithmeticCalculator.add(1, 2);
arithmeticCalculator.sub(4, 3);
arithmeticCalculator.mul(2, 3);
arithmeticCalculator.div(4, 0);
unitCalculator.kilogramToPound(10);
unitCalculator.kilometerToMile(5);