沙漠中的魚

          欲上天堂,先下地獄
          posts - 0, comments - 56, trackbacks - 0, articles - 119
            BlogJava :: 首頁 ::  :: 聯系 :: 聚合  :: 管理
          AOP:Aspect Oriented Programming,意為面向切面/局部的程序設計。它是面向對象的程序設計的一種延伸。

          本文試圖通過使用Java本身的動態屬性,來實現一個具有簡單的AOP功能的容器。

          開始理解起來可能比較費勁,但我們可以通過一個通俗說明來這樣理解AOP的概念,就是使用AOP可以不用修改原有的代碼,而可以追加新的功能。

          比如,我們用AOP實現了用戶登陸(判斷ID與密碼是否正確)功能,現在我們要求在用戶登陸時用LOG記錄用戶登陸的情況。一般的做法是直接修改已有的登陸邏輯代碼,但使用AOP,可以不用修改原有的代碼而完成此功能。


          本文試圖通過使用Java本身的動態代理功能,來實現一個具有簡單的AOP功能的容器。從而幫助大家對AOP有個大概的認識。

          Java動態代理功能
          首先,我們簡單介紹一下Java動態代理功能。JAVA的動態代理功能主要通過java.lang.reflect.Proxy類與java.lang.reflect.InvocationHandler接口完成,這里正是通過它們實現一個簡單的AOP容器的。其實,像JBoss AOP等其他動態AOP框架也都是通過Proxy和InvocationHandler來實現的。


          • Java從JDK1.3開始提供動態代理(Java Proxy)功能。
          • 所謂動態代理,即通過代理類:Proxy的代理,接口和實現類之間可以不直接發生聯系,而可以在運行期(Runtime)實現動態關聯。
          • AOP(Aspect Oriented Programming):面向切面編程,其中的一種實現方法便是用Proxy來實現的。
          • Java Proxy只能代理接口,不能代理類。
          • Java Proxy功能主要通過java.lang.reflect.Proxy類與java.lang.reflect.InvocationHandler接口實現。
          • java.lang.reflect.Proxy (代理類) > ProxyInterface(被代理的接口)   > InvocationHandler(關聯類)> Class(可以在InvocationHandler中被調用)。它們之間的關系可以用下面的流程圖來表示:


          動態代理類:Proxy 被代理的接口 InvocationHandler實現類 代理類

               實際上的調用關系可以用下面的流程圖來表示:

          Proxy.newProxyInstance

          XxxxInterface xx = $ProxyN(N=0,1,2…)

          XxxxInterface.calledMethod

          $ProxyN.calledMethod

          InvocationHandler.invoke

          method.invoke(obj, args)

          obj.calledMethod
          1. Proxy. newProxyInstance的參數:必須傳送以下3個參數給Proxy. newProxyInstance方法:ClassLoader,Class[],InvocationHandler。其中參數2為被代理的接口 Class,參數3為實現InvocationHandler接口的實例。
          2. 可以通過Proxy. newProxyInstance方法得到被代理的接口的一個實例(instance),該實例由newProxyInstance方法動態生成,并實現了該接口。
          3. 當程序顯示調用接口的方法時,其時是調用該實例的方法,此方法又會調用與該實例相關聯InvocationHandler的invoke方法。
          4. 這樣我們可以在InvocationHandler.invoke方法里調用某些處理邏輯或真正的邏輯處理實現類。



          用Java Proxy實現AOP容器
          下面我們使用Java Proxy來實現一個簡單的AOP容器。
          文件列表:
          文件名 說明
          AopInvocationHandlerImpl.java 該類實現了java.lang.reflect.InvocationHandler接口,我們通過它記錄LOG信息
          AopContainer.java 簡單的AOP容器,通過它把IDoBusiness與AopInvocationHandlerImpl關聯起來
          IDoBusiness.java 邏輯處理接口
          DoBusiness.java 邏輯處理實現類
          TestAop.java 測試類

          簡單的AOP容器:
          AopContainer.java
          package com.test.aop.framework;

          import java.lang.reflect.Proxy;

          /**
          * A Simple AOP Container
          *
          */

          public class AopContainer {
              public static <T> T getBean(Class<T> interfaceClazz, final T obj) {
                   assert interfaceClazz.isInterface();
                  
                  return (T) Proxy.newProxyInstance(interfaceClazz.getClassLoader(),
                          new Class[] { interfaceClazz }, new AopInvocationHandlerImpl(obj));
               }

              public static Object getBean(final Object obj) {
                  return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                           obj.getClass().getInterfaces(), new AopInvocationHandlerImpl(obj));
               }
          }
          第一個getBean方法通過2個參數(第一個參數為被代理的接口,第二個參數為被代理的類實例)
          第二個getBean方法只有一個參數,就是類的實例。該類必須實現1個以上的接口。本文的例子并沒有使用到該方法,所以這里順便介紹一下它的使用方法。比如有一個類HelloWorld實現了接口IHelloWorld1和IHelloWorld2,那么可以通過
          HelloWorld helloWorld = new HelloWorld();
          IHelloWorld1 helloWorld1 = (IHelloWorld1)AopContainer.getBean(helloWorld);
          //或
          IHelloWorld2 helloWorld2 = (IHelloWorld2)AopContainer.getBean(helloWorld);
          調用。當然很多時候都不會直接用new HelloWorld()生成HelloWorld實例,這里為了簡便,就直接用new生成HelloWorld實例了。

          實現InvocationHandler接口的中間類:
          AopInvocationHandlerImpl.java
          package com.test.aop.framework;

          import java.lang.reflect.InvocationHandler;
          import java.lang.reflect.Method;

          public class AopInvocationHandlerImpl implements InvocationHandler {
              private Object bizPojo;
              
              public AopInvocationHandlerImpl(Object bizPojo) {
                   this.bizPojo = bizPojo;
               }

              /*
               * (non - Javadoc)
               *
               * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
               *       java.lang.reflect.Method, java.lang.Object[])
               */

              public Object invoke(Object proxy, Method method, Object[] args)
                      throws Throwable {
                   Object o = null;
                  try {
                       System.out.println("Start:" + method.getName());
                       o = method.invoke(bizPojo, args);
                       System.out.println("End:" + method.getName());
                   } catch (Exception e) {
                       e.printStackTrace();
                       System.out.println("Exception Occured!" + e.getMessage());
                      // excetpion handling.
                   }
                  return o;
               }
          }
          AopInvocationHandlerImpl.invoke方法的第一個參數為代理類,在我們這個例子里為java.lang.reflect.Proxy類的一個實例。第二個參數Method,為被代理的接口的方法調用(實際上是自動生成代理類的方法調用),第三個方法為方法調用的參數。
          我們通過在AopInvocationHandlerImpl.invoke方法里的method.invoke(bizPojo, args)來調用bizPojo類的與被代理接口的同名方法。這里,bizPojo必須實現了被代理的接口。
          在我們的例子里,我們在實際上被調用的業務邏輯方法的前后輸出了日志信息。

          實際上的邏輯處理類。該類實現了被代理的接口:IDoBusiness。
          DoBusiness.java
          package com.test.aop.framework;

          /**
          * A business class
          *
          */

          public class DoBusiness implements IDoBusiness {
              public void printNothing() {
                   System.out.println("Just Say Hello!");
               }
              
              public void throwException() {
                  throw new RuntimeException("throw Exception from DoBusiness.throwException()");
               }

          }

          被代理的接口定義:
          IDoBusiness.java
          package com.test.aop.framework;

          /**
          * interface for business logic process
          *
          */

          public interface IDoBusiness {
              public void printNothing();
              public void throwException();
          }

          測試類:
          TestAop.java
          package com.test.aop.framework;


          /**
          * Test AOP
          *
          */

          public class TestAop {

              /**
               * @param args
               */

              public static void main(String[] args) {
                   DoBusiness doBusiness = new DoBusiness();
                   IDoBusiness idoBusiness = AopContainer.getBean(IDoBusiness.class, doBusiness);
                   idoBusiness.printNothing();
                  
                   idoBusiness.throwException();
               }

          }

          總結:
          本文通過Java Proxy實現了一個簡單地AOP容器。也簡單地展示了AOP的基本實現原理,實際上可以以此為基礎實現一個功能完善的AOP容器。

           

          轉載:http://hi.baidu.com/e9151/blog/item/9c8d772be0319d305243c130.html

          主站蜘蛛池模板: 阿坝| 开化县| 天气| 图们市| 大余县| 哈巴河县| 玉溪市| 舒兰市| 团风县| 邳州市| 富锦市| 永修县| 安泽县| 郓城县| 威信县| 宁陕县| 兴业县| 梁河县| 名山县| 社旗县| 日照市| 拜泉县| 乐东| 西吉县| 霍邱县| 潞西市| 勃利县| 理塘县| 盘山县| 乌苏市| 黎川县| 汾西县| 利川市| 石柱| 扎兰屯市| 吐鲁番市| 永康市| 田阳县| 井研县| 贵港市| 宁陕县|