1 准备例子
class="MsoNormal" style="text-indent: 24.0pt;">AOP为开发者定义了一组高层次的概念,用于表达横切关注点。在某个特定的执行点所执行的横切动作被封装在通知里(advice)里。为了更好地理解横切关注点,这里引入一个简单的计算器的例子。
首先,创建一个接口ArithmeticCalculator,处理算术计算。
package org.mahz.easyaop.calculator;
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);
}
接下来为每个计算器接口提供一个简单的实现。当这些方法为执行时println语句会给出提示。
package org.mahz.easyaop.calculator.impl;
import org.mahz.easyaop.calculator.ArithmeticCalculator;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {	
	
        private double result;
	
	public double add(double a, double b) {
		result = a + b;
		printResult(a, b, " + ");
		return result;
	}
	public double sub(double a, double b) {
		result = a - b;
		printResult(a, b, " - ");
		return result;
	}
	public double mul(double a, double b) {
		result =  a * b;
		printResult(a, b, " * ");
		return result;
	}
	public double div(double a, double b) {
                if(b == 0)
		    throw new IllegalArgumentException("Division by zero");
		result = a / b;
		printResult(a, b, " / ");
		return result;
	}
	public void printResult(double a, double b, String operation){
		System.out.println(a + operation + b + " = " + result);
	}
}
将计算机应用程序放到Spring IoC容器里运行。在Spring的Bean配置文件里声明这个计算器。
<bean id="arithmeticCalculator" class="org.mahz.easyaop.calculator.impl.ArithmeticCalculatorImpl" />
编写Client类来测试这个计算器的基本功能。
package org.mahz.easyaop.client; import org.mahz.easyaop.calculator.ArithmeticCalculator; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "bean.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) context .getBean("arithmeticCalculator"); double a = 4; double b = 2; arithmeticCalculator.add(a, b); arithmeticCalculator.sub(a, b); arithmeticCalculator.mul(a, b); arithmeticCalculator.div(a, b); } }
经典的Spring AOP支持4种类型的通知,它们分别作用于执行点的不同时间。不过,Spring AOP只支持方法执行。
前置通知(before advice):在方法执行之前。
返回通知(after returing advice):在方法执行之后。
异常通知(after throwing advice):在方法抛出异常之后。
环绕通知(around advice):围绕着方法执行。
??? 前置通知在方法执行之前执行。可以通过实现MethodBeforeAdvice接口创建它。在before()方法,你能获取到目标方法的细节及其参数。
package org.mahz.easyaop.calculator.aop;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.aop.MethodBeforeAdvice;
public class LoggingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("==========================================");
		System.out.println("============ Test " + method.getName()
				+ " Method =============");
		System.out.println("==========================================");
		System.out.println("The method " + method.getName() + "()begin with "
				+ Arrays.toString(args));
	}
}
返回通知,记录方法的结束以及返回的结果。
package org.mahz.easyaop.calculator.aop;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class LoggingAfterAdvice implements AfterReturningAdvice {
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("The Method " + method.getName() + "() ends with "
				+ returnValue);
	}
}
对于异常通知类型来说,必须实现ThrowsAdvice接口。请注意,这个接口没有声明任何方法。这样就能够在不同的方法里处理不同类型的异常了,不过,每个处理方法的名称必须是afterThrowing。异常的类型由方法的参数类型指定。
package org.mahz.easyaop.calculator.aop;
import org.springframework.aop.ThrowsAdvice;
public class LoggingThrowsAdvice implements ThrowsAdvice {
	public void afterThrowing(IllegalArgumentException e) throws Throwable {
		System.out.println(e.getMessage());
	}
}
??? 准备好通知之后,下一步就是在计算器Bean上应用通知。首先,必须在IoC容器里声明该通知的实例。然后,使用Spring AOP提供的一个叫做自动代理创建器,可以为Bean自动创建代理。有了自动代理创建器,就不再需要使用ProxyFactoryBean手工地创建代理了。
<bean id="arithmeticCalculator" class="org.mahz.easyaop.calculator.impl.ArithmeticCalculatorImpl" /> <bean id="logginBeforeAdvice" class="org.mahz.easyaop.calculator.aop.LoggingBeforeAdvice" /> <bean id="logginAfterAdvice" class="org.mahz.easyaop.calculator.aop.LoggingAfterAdvice" /> <bean id="logginThrowsAdvice" class="org.mahz.easyaop.calculator.aop.LoggingThrowsAdvice" /> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>*Calculator</value> </list> </property> <property name="interceptorNames"> <list> <value>logginBeforeAdvice</value> <value>logginAfterAdvice</value> <value>logginThrowsAdvice</value> </list> </property> </bean>