深入探索spring技术内幕(五): 剖析spring AOP工作原理

一、前言

AOP (Aspect Oriented Programing) - 面向切面编程,它主要用于日志记录、性能分析、安全控制、事务处理、异常处理等方面。

AOP主要使用JDK的反射和动态代理,AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理包含了目标对象的全部方法,但AOP代理的方法与目标对象的方法存在差异:AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。


动态代理的文章请参考:http://blog.csdn.net/zdp072/article/details/24868895


二、实现细节

下面这个例子利用AOP来实现日志记录:

附上一张类的结构图,该例子需要导入dom4j.jar


业务逻辑接口

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 业务逻辑类接口 
  3.  * @author zhangjim 
  4.  */  
  5. public interface BusinessService {  
  6.     /** 
  7.      * 处理业务 
  8.      */  
  9.     public void process();  
  10. }  
② 业务逻辑实现

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 业务逻辑对象实现类 
  3.  * @author zhangjim 
  4.  */  
  5. public class BusinessServiceImpl implements BusinessService {  
  6.     /** 
  7.      * 处理业务 
  8.      */  
  9.     public void process() {  
  10.         System.out.println("process business logic...");  
  11.     }  
  12. }  
③ 通知类接口

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 通知类接口 
  3.  * @author zhangjim 
  4.  */  
  5. public interface Advisor {  
  6.     /** 
  7.      * 所做的操作 
  8.      */  
  9.     public void doInAdvisor(Object proxy, Method method, Object[] args);  
  10. }  
④ 方法的前置通知

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import java.lang.reflect.Method;  
  2.   
  3. /** 
  4.  * 方法前置通知,它完成方法的前置操作 
  5.  * @author zhangjim 
  6.  */  
  7. public class BeforeMethodAdvisor implements Advisor {  
  8.     /** 
  9.      * 在方法执行前所进行的操作 
  10.      */  
  11.     public void doInAdvisor(Object proxy, Method method, Object[] args) {  
  12.         System.out.println("before process... ");  
  13.     }  
  14. }  
⑤ 方法的后置通知

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 方法的后置通知,它完成方法的后置操作 
  3.  * @author zhangjim 
  4.  */  
  5. public class AfterMethodAdvisor implements Advisor {  
  6.     /** 
  7.      * 在方法执行后所进行的操作 
  8.      */  
  9.     public void doInAdvisor(Object proxy, Method method, Object[] args) {  
  10.         System.out.println("after process...");  
  11.     }  
  12. }  
⑥ AOP处理器

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import java.lang.reflect.InvocationHandler;  
  2. import java.lang.reflect.Method;  
  3. import java.lang.reflect.Proxy;  
  4. import com.zdp.advisor.Advisor;  
  5.   
  6. /** 
  7.  * AOP处理器 
  8.  * @author zhangjim 
  9.  */  
  10. public class AopHandler implements InvocationHandler {  
  11.     private Object target; // 需要代理的目标对象  
  12.     Advisor beforeAdvisor; // 方法前置通知  
  13.     Advisor afterAdvisor; // 方法后置通知  
  14.   
  15.     /** 
  16.      * 设置代理目标对象,并生成动态代理对象. 
  17.      * @param target 代理目标对象 
  18.      * @return 返回动态代理对象 
  19.      */  
  20.     public Object setObject(Object target) {  
  21.         this.target = target; // 设置代理目标对象   
  22.         Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); // 根据代理目标对象生成动态代理对象  
  23.         return proxy;  
  24.     }  
  25.   
  26.     /** 
  27.      * 若定义了前置处理,则在方法执行前执行前置处理, 若定义了后置处理,则在方法调用后调用后置处理. 
  28.      *  
  29.      * @param proxy 代理对象 
  30.      * @param method 调用的业务方法 
  31.      * @param args 方法的参数 
  32.      * @return 返回结果信息 
  33.      * @throws Throwable 
  34.      */  
  35.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  36.         if (beforeAdvisor != null) {   
  37.             beforeAdvisor.doInAdvisor(proxy, method, args); // 进行业务方法的前置处理  
  38.         }  
  39.         method.invoke(target, args); // 执行业务方法  
  40.         if (afterAdvisor != null) {  
  41.             afterAdvisor.doInAdvisor(proxy, method, args); // 进行业务方法的后置处理  
  42.         }  
  43.         return null// 返回结果对象  
  44.     }  
  45.   
  46.     /** 
  47.      * 设置方法的前置通知 
  48.      * @param advisor 方法的前置通知 
  49.      */  
  50.     public void setBeforeAdvisor(Advisor advisor) {  
  51.         this.beforeAdvisor = advisor;  
  52.     }  
  53.   
  54.     /** 
  55.      * 设置方法的后置通知 
  56.      * @param advisor 方法的后置通知 
  57.      */  
  58.     public void setAfterAdvisor(Advisor advisor) {  
  59.         this.afterAdvisor = advisor;  
  60.     }  
  61. }  
⑦ Bean工厂类

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import java.io.InputStream;  
  2. import java.util.HashMap;  
  3. import java.util.Iterator;  
  4. import java.util.Map;  
  5. import org.dom4j.Attribute;  
  6. import org.dom4j.Document;  
  7. import org.dom4j.Element;  
  8. import org.dom4j.io.SAXReader;  
  9. import com.zdp.advisor.Advisor;  
  10.   
  11. /** 
  12.  * Bean工厂类 
  13.  * @author zhangjim 
  14.  */  
  15. public class BeanFactory {  
  16.     private Map<String, Object> beansMap = new HashMap<String, Object>();   
  17.   
  18.     /** 
  19.      * Bean工厂的初始化 
  20.      */  
  21.     public void init(String xml) {  
  22.         try {  
  23.             SAXReader reader = new SAXReader();  
  24.             ClassLoader classLoader = Thread.currentThread().getContextClassLoader();  
  25.             InputStream ins = classLoader.getResourceAsStream(xml); // 读取指定的配置文件  
  26.             Document doc = reader.read(ins);  
  27.             Element root = doc.getRootElement();  
  28.             AopHandler aopHandler = new AopHandler(); // 创建AOP处理器(动态生成的proxy类中持有了aopHandle的引用)  
  29.             for (Iterator iter = root.elementIterator("bean"); iter.hasNext();) { // 遍历bean   
  30.                 Element element = (Element) iter.next();   
  31.                 Attribute id = element.attribute("id"); // 获取bean的属性id、class、aopClass、aopType  
  32.                 Attribute cls = element.attribute("class");  
  33.                 Attribute aopClass = element.attribute("aopClass");   
  34.                 Attribute aopType = element.attribute("aopType");  
  35.                   
  36.                 if (aopClass != null && aopType != null) { // 如果配置了aopClass和aopType属性时,需进行拦截操作  
  37.                     Class advisorClass = Class.forName(aopClass.getText()); // 根据aopClass字符串获取对应的类  
  38.                     Advisor advisor = (Advisor) advisorClass.newInstance(); // 创建该类的对象   
  39.                     if ("before".equals(aopType.getText())) { // 根据aopType的类型来设置前置或后置顾问  
  40.                         aopHandler.setBeforeAdvisor(advisor);   
  41.                     } else if ("after".equals(aopType.getText())) {  
  42.                         aopHandler.setAfterAdvisor(advisor);  
  43.                     }  
  44.                 }  
  45.   
  46.                 Class clazz = Class.forName(cls.getText()); // 利用Java反射机制,通过class的名称获取Class对象   
  47.                 Object obj = clazz.newInstance(); // 创建一个对象   
  48.                   
  49.                 Object proxy = (Object) aopHandler.setObject(obj); // 产生代理对象proxy  
  50.                 beansMap.put(id.getText(), proxy); // 将对象放入beansMap中,其中id为key,对象为value  
  51.             }  
  52.         } catch (Exception e) {  
  53.             System.out.println(e.toString());  
  54.         }  
  55.     }  
  56.   
  57.     /** 
  58.      * 通过bean的id获取bean的对象. 
  59.      * @param beanName bean的id 
  60.      * @return 返回对应对象 
  61.      */  
  62.     public Object getBean(String beanName) {  
  63.         Object obj = beansMap.get(beanName);  
  64.         return obj;  
  65.     }  
  66. }  
⑧ 配置文件beans.xml

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans>  
  3.     <bean id="businessService" class="com.zdp.service.BusinessServiceImpl"   
  4.     aopClass="com.zdp.advisor.BeforeMethodAdvisor" aopType="before"></bean>  
  5. </beans>  

⑨ 测试类

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import com.zdp.service.BusinessService;  
  2. import com.zdp.spring.BeanFactory;  
  3. /** 
  4.  * 测试类 
  5.  * @author zhangjim 
  6.  */  
  7. public class Client {  
  8.     public static void main(String[] args) {  
  9.         BeanFactory beanFactory = new BeanFactory();    
  10.         beanFactory.init("beans.xml");  
  11.         BusinessService proxy = (BusinessService) beanFactory.getBean("businessService");  
  12.         proxy.process();  
  13.     }  
  14. }  


三、小结

上文仅仅是简单地模拟了spring的AOP的实现,但还是很好地展现了JDK反射和动态代理在spring中的应用,对于初学者理解AOP应该会有一点帮助。 

源码下载地址: http://download.csdn.net/detail/zdp072/7284987

参考资料:http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值