walterwing  
          日歷
          <2008年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789
          統計
          • 隨筆 - 12
          • 文章 - 1
          • 評論 - 7
          • 引用 - 0

          導航

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

           
          今天讀了讀夏昕寫的《Spring開發指南》,在“AOP in Spring”一節,作者講述了Spring中如何通過動態AOP來提供內置的AOP支持。“從技術角度來講,所謂動態AOP,即通過動態Proxy模式,在目標對象的方法調用前后插入相應的處理代碼”

          作者舉了一些例子來解釋何為靜態Proxy,何為動態Proxy。奈何我根基尚淺,最作者舉的動態Proxy的例子懵懂不解,于是自己嘗試著摸索一番,終于對動態Proxy的用法有了一個初步的認識。

          首先還是來看靜態Proxy,就我目前的認識看來,Proxy的主要用途是對類中方法的執行進行一下包裝,在方法執行之前,或之后,或both,加入一些“額外”的操作。典型的應用就是加入事務處理。

          靜態Proxy相對來講比較簡單,它是對上面所述思想的一個最直接的實現。

          假設我們現在有如下一個接口:

          package aop;

          public interface Foo {
              
          public String getMessage(String arg);
          }

          以及該接口的一個實現類:

          package aop;

          public class FooImpl implements Foo {

              
          public String getMessage(String arg) {
                  
          return "hi " + arg;
              }


          }


          那么很容易,我們可以通過如下方式進行調用:

          package aop;

          public class Test {

              
          /**
               * 
          @param args
               
          */

              
          public static void main(String[] args) {
                  Foo foo 
          = new FooImpl();
                  String message 
          = foo.getMessage("Wing");
                  System.out.println(message);
              }


          }


          輸出結果:
          hi Wing


          現在問題來了:如果現在我們想在getMessage()之外添加一些額外的操作,比如在這之前輸出“Begin”,在之后輸出“done”,但又不能改變原有接口,怎么辦?也很簡單,用靜態Proxy就可以很方便的實現:

          package aop;

          public class StaticProxy implements Foo {
              
          private Foo foo;
              
              
          public StaticProxy(Foo foo) {
                  
          this.foo = foo;
              }

              
              
          public void getMessage(String arg) {
                  System.out.println(
          "Begin!");
                  
                  String message 
          = foo.getMessage(arg);
                  System.out.println(message);
                  
                  System.out.println(
          "Done!");
              }

          }


          調用:

          package aop;

          public class TestStaticProxy {

              
          /**
               * 
          @param args
               
          */

              
          public static void main(String[] args) {
                  Foo foo 
          = new StaticProxy(new FooImpl());
                  foo.getMessage(
          "Wing");
              }


          }


          結果:

          Begin!
          hi Wing
          Done
          !

          你可以看到,StaticProxy只是在Foo的某實現類基礎上包了一層,當然我們這里加的兩個輸出語句無足輕重,但如果我們把這兩個輸出語句替換成事務處理,意義就大不一樣了。

          可見,通過靜態Proxy可以實現我們的需求,但如果我們有十幾、二十個這樣的接口實現類,需要類似的處理,我們怎么辦?難道每個實現類都對應一個Proxy嗎?

          這時,我們就需要動態Proxy:

          package aop;

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

          public class AOPHandler implements InvocationHandler {
              
              
          private Object orginal;
              
              
          public Object bind(Object obj) {
                  orginal 
          = obj;
                  
          return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
              }


              
          public Object invoke(Object proxy, Method method, Object[] args)
                      
          throws Throwable {
                  System.out.println(
          "Begin!");
                  
                  Object result 
          = method.invoke(orginal, args);
                  System.out.println(result);
                  
                  System.out.println(
          "Done!");
                  
                  
          return result;
              }


          }



          第一次看到上面的代碼肯定不知所以,稍后解釋,我們先看如何調用:

          package aop;

          public class TestAOP {

              
          /**
               * 
          @param args
               
          */

              
          public static void main(String[] args) {
                  AOPHandler handler 
          = new AOPHandler();
                  Object proxy 
          = handler.bind(new FooImpl());
                  
                  String message 
          = ((Foo) proxy).getMessage("Wing");
                  
                  System.out.println(message);
              }


          }



          結果:

          Begin!
          hi Wing
          Done
          !
          hi Wing

          下面來解釋一下AOPHandler這個類:

          首先,bind()方法是用來創建動態Proxy實例。動態Proxy也是Proxy,和靜態Proxy一樣,功能上都是為了在調用某接口實現類的方法之余,添加一些額外的操作(比如事務處理),他們(動態和靜態Proxy)都是一種特殊的接口實現類。因此,我們在調用的時候可以用
          String message = ((Foo) proxy).getMessage("Wing");
          把proxy實例直接cast為Foo類型,并調用foo接口上的方法。

          不同的是,靜態Proxy,正如前面看到的,是直接實現了接口,并在接口的方法中直接調用該接口某實現類對應的方法。而動態Proxy,是利用Java.lang.reflect.Proxy類提供的這樣一種機制:當構建Proxy時,我們需要提供接口,以及一個關聯的調用處理程序對象(通常實現了InvocationHandler接口),當我們在Proxy上調用接口上的方法(任意方法)時,將觸發調用InvocationHandler接口定義的invoke()方法,由invoke方法完成相應的操作。

          上面的AOPHandler類,是將動態Proxy的構建與InvocationHandler接口的實現結合在了一起。

          通過AOPHandler,我們可以在運行時期動態的決定用哪個接口實現類來創建Proxy,而不需事先為每個實現類定義對應的Proxy,靈活性和復用性大大增強。

          進一步的,我們可以利用java反射機制,通過類名來得到接口實現類的實例,進而得到該實例的動態Proxy。這樣我們就可以在配置文件里動態指定需要用到的接口實現類,就像Spring中所做的一樣。
          posted on 2008-07-09 15:08 This is Wing 閱讀(423) 評論(0)  編輯  收藏 所屬分類: Java基礎
           
          Copyright © This is Wing Powered by: 博客園 模板提供:滬江博客
          主站蜘蛛池模板: 高雄市| 襄城县| 鄯善县| 凯里市| 长丰县| 宣汉县| 沙河市| 垣曲县| 双江| 泸西县| 无棣县| 安徽省| 辽阳县| 安多县| 渝中区| 光泽县| 聊城市| 容城县| 湖北省| 承德市| 武冈市| 赞皇县| 英山县| 普洱| 东平县| 蒙山县| 华亭县| 神池县| 南乐县| 小金县| 神木县| 达孜县| 金沙县| 西林县| 高密市| 建瓯市| 东海县| 泽州县| 遂宁市| 如皋市| 中宁县|