一、前言
AOP (Aspect Oriented Programing) - 面向切面编程,它主要用于日志记录、性能分析、安全控制、事务处理、异常处理等方面。
AOP主要使用JDK的反射和动态代理,AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理包含了目标对象的全部方法,但AOP代理的方法与目标对象的方法存在差异:AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。
动态代理的文章请参考:http://blog.csdn.net/zdp072/article/details/24868895
二、实现细节
下面这个例子利用AOP来实现日志记录:
附上一张类的结构图,该例子需要导入dom4j.jar
①业务逻辑接口
- /**
- * 业务逻辑类接口
- * @author zhangjim
- */
- public interface BusinessService {
- /**
- * 处理业务
- */
- public void process();
- }
- /**
- * 业务逻辑对象实现类
- * @author zhangjim
- */
- public class BusinessServiceImpl implements BusinessService {
- /**
- * 处理业务
- */
- public void process() {
- System.out.println("process business logic...");
- }
- }
- /**
- * 通知类接口
- * @author zhangjim
- */
- public interface Advisor {
- /**
- * 所做的操作
- */
- public void doInAdvisor(Object proxy, Method method, Object[] args);
- }
- import java.lang.reflect.Method;
- /**
- * 方法前置通知,它完成方法的前置操作
- * @author zhangjim
- */
- public class BeforeMethodAdvisor implements Advisor {
- /**
- * 在方法执行前所进行的操作
- */
- public void doInAdvisor(Object proxy, Method method, Object[] args) {
- System.out.println("before process... ");
- }
- }
- /**
- * 方法的后置通知,它完成方法的后置操作
- * @author zhangjim
- */
- public class AfterMethodAdvisor implements Advisor {
- /**
- * 在方法执行后所进行的操作
- */
- public void doInAdvisor(Object proxy, Method method, Object[] args) {
- System.out.println("after process...");
- }
- }
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import com.zdp.advisor.Advisor;
- /**
- * AOP处理器
- * @author zhangjim
- */
- public class AopHandler implements InvocationHandler {
- private Object target; // 需要代理的目标对象
- Advisor beforeAdvisor; // 方法前置通知
- Advisor afterAdvisor; // 方法后置通知
- /**
- * 设置代理目标对象,并生成动态代理对象.
- * @param target 代理目标对象
- * @return 返回动态代理对象
- */
- public Object setObject(Object target) {
- this.target = target; // 设置代理目标对象
- Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); // 根据代理目标对象生成动态代理对象
- return proxy;
- }
- /**
- * 若定义了前置处理,则在方法执行前执行前置处理, 若定义了后置处理,则在方法调用后调用后置处理.
- *
- * @param proxy 代理对象
- * @param method 调用的业务方法
- * @param args 方法的参数
- * @return 返回结果信息
- * @throws Throwable
- */
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (beforeAdvisor != null) {
- beforeAdvisor.doInAdvisor(proxy, method, args); // 进行业务方法的前置处理
- }
- method.invoke(target, args); // 执行业务方法
- if (afterAdvisor != null) {
- afterAdvisor.doInAdvisor(proxy, method, args); // 进行业务方法的后置处理
- }
- return null; // 返回结果对象
- }
- /**
- * 设置方法的前置通知
- * @param advisor 方法的前置通知
- */
- public void setBeforeAdvisor(Advisor advisor) {
- this.beforeAdvisor = advisor;
- }
- /**
- * 设置方法的后置通知
- * @param advisor 方法的后置通知
- */
- public void setAfterAdvisor(Advisor advisor) {
- this.afterAdvisor = advisor;
- }
- }
- import java.io.InputStream;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import org.dom4j.Attribute;
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- import com.zdp.advisor.Advisor;
- /**
- * Bean工厂类
- * @author zhangjim
- */
- public class BeanFactory {
- private Map<String, Object> beansMap = new HashMap<String, Object>();
- /**
- * Bean工厂的初始化
- */
- public void init(String xml) {
- try {
- SAXReader reader = new SAXReader();
- ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
- InputStream ins = classLoader.getResourceAsStream(xml); // 读取指定的配置文件
- Document doc = reader.read(ins);
- Element root = doc.getRootElement();
- AopHandler aopHandler = new AopHandler(); // 创建AOP处理器(动态生成的proxy类中持有了aopHandle的引用)
- for (Iterator iter = root.elementIterator("bean"); iter.hasNext();) { // 遍历bean
- Element element = (Element) iter.next();
- Attribute id = element.attribute("id"); // 获取bean的属性id、class、aopClass、aopType
- Attribute cls = element.attribute("class");
- Attribute aopClass = element.attribute("aopClass");
- Attribute aopType = element.attribute("aopType");
- if (aopClass != null && aopType != null) { // 如果配置了aopClass和aopType属性时,需进行拦截操作
- Class advisorClass = Class.forName(aopClass.getText()); // 根据aopClass字符串获取对应的类
- Advisor advisor = (Advisor) advisorClass.newInstance(); // 创建该类的对象
- if ("before".equals(aopType.getText())) { // 根据aopType的类型来设置前置或后置顾问
- aopHandler.setBeforeAdvisor(advisor);
- } else if ("after".equals(aopType.getText())) {
- aopHandler.setAfterAdvisor(advisor);
- }
- }
- Class clazz = Class.forName(cls.getText()); // 利用Java反射机制,通过class的名称获取Class对象
- Object obj = clazz.newInstance(); // 创建一个对象
- Object proxy = (Object) aopHandler.setObject(obj); // 产生代理对象proxy
- beansMap.put(id.getText(), proxy); // 将对象放入beansMap中,其中id为key,对象为value
- }
- } catch (Exception e) {
- System.out.println(e.toString());
- }
- }
- /**
- * 通过bean的id获取bean的对象.
- * @param beanName bean的id
- * @return 返回对应对象
- */
- public Object getBean(String beanName) {
- Object obj = beansMap.get(beanName);
- return obj;
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans>
- <bean id="businessService" class="com.zdp.service.BusinessServiceImpl"
- aopClass="com.zdp.advisor.BeforeMethodAdvisor" aopType="before"></bean>
- </beans>
⑨ 测试类
- import com.zdp.service.BusinessService;
- import com.zdp.spring.BeanFactory;
- /**
- * 测试类
- * @author zhangjim
- */
- public class Client {
- public static void main(String[] args) {
- BeanFactory beanFactory = new BeanFactory();
- beanFactory.init("beans.xml");
- BusinessService proxy = (BusinessService) beanFactory.getBean("businessService");
- proxy.process();
- }
- }
三、小结
上文仅仅是简单地模拟了spring的AOP的实现,但还是很好地展现了JDK反射和动态代理在spring中的应用,对于初学者理解AOP应该会有一点帮助。
源码下载地址: http://download.csdn.net/detail/zdp072/7284987
参考资料:http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/