qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          Java 代理(proxy)模式

          代理模式(Proxy Pattern)
            代理模式是常用的Java 設計模式,它的特征是代理類與委托類有同樣的接口,代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的對象本身并不真正實現服務,而是通過調用委托類的對象的相關方法,來提供特定的服務。
            如下列子:
          package proxy;
          interface Dao{
          public void insert();
          }
          class JdbcDao implements Dao{
          public void insert(){
          System.out.println("in jdbc insert");
          }
          }
          class HibernateDao implements Dao{
          public void insert(){
          System.out.println("in hibernate insert");
          }
          }
          class ProxyDao implements Dao{
          private Dao dao;
          public ProxyDao(Dao dao){
          this.dao=dao;
          }
          public void insert() {
          System.out.println("write log before invoke");
          dao.insert();
          System.out.println("write log after invoke");
          }
          }
          public class Test {
          public static void main(String[] args) {
          Dao jdbcDao =new JdbcDao();
          Dao proxydao = new ProxyDao(jdbcDao);
          proxydao.insert();
          }
          }
            運行結果:
            write log before invoke
            in jdbc insert
            write log after invoke
            隨著Proxy的流行,Sun把它納入到JDK1.3實現了Java的動態代理。動態代理和普通的代理模式的區別,就是動態代理中的代理類是由 java.lang.reflect.Proxy類在運行期時根據接口定義,采用Java反射功能動態生成的。和 java.lang.reflect.InvocationHandler結合,可以加強現有類的方法實現。如圖2,圖中的自定義Handler實現 InvocationHandler接口,自定義Handler實例化時,將實現類傳入自定義Handler對象。自定義Handler需要實現 invoke方法,該方法可以使用Java反射調用實現類的實現的方法,同時當然可以實現其他功能,例如在調用實現類方法前后加入Log。而Proxy類根據Handler和需要代理的接口動態生成一個接口實現類的對象。當用戶調用這個動態生成的實現類時,實際上是調用了自定義Handler的 invoke方法。
            Proxy類提供了創建動態代理類及其實例的靜態方法。
            (1)getProxyClass()靜態方法負責創建動態代理類,它的完整定義如下:
            public static Class<?> getProxyClass(ClassLoader loader, Class<?>[] interfaces) throws IllegalArgumentException
            參數loader 指定動態代理類的類加載器,參數interfaces 指定動態代理類需要實現的所有接口。
            (2)newProxyInstance()靜態方法負責創建動態代理類的實例,它的完整定義如下:
            public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws
            IllegalArgumentException
            參數loader 指定動態代理類的類加載器,參數interfaces 指定動態代理類需要實現的所有接口,參數handler 指定與動態代理類關聯的 InvocationHandler 對象。
            以下兩種方式都創建了實現Foo接口的動態代理類的實例:
            /**** 方式一 ****/
            //創建InvocationHandler對象
            InvocationHandler handler = new MyInvocationHandler(...);
            //創建動態代理類
            Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });
            //創建動態代理類的實例
            Foo foo = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).
            newInstance(new Object[] { handler });
            /**** 方式二 ****/
            //創建InvocationHandler對象
            InvocationHandler handler = new MyInvocationHandler(...);
            //直接創建動態代理類的實例
            Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] { Foo.class }, handler);
            由Proxy類的靜態方法創建的動態代理類具有以下特點:
            動態代理類是public、final和非抽象類型的;
            動態代理類繼承了java.lang.reflect.Proxy類;
            動態代理類的名字以“$Proxy”開頭;
            動態代理類實現getProxyClass()和newProxyInstance()方法中參數interfaces指定的所有接口;
            Proxy 類的isProxyClass(Class<?> cl)靜態方法可用來判斷參數指定的類是否為動態代理類。只有通過Proxy類創建的類才是動態代理類;
            動態代理類都具有一個public 類型的構造方法,該構造方法有一個InvocationHandler 類型的參數。
            由Proxy類的靜態方法創建的動態代理類的實例具有以下特點:
            1. 假定變量foo 是一個動態代理類的實例,并且這個動態代理類實現了Foo 接口,那么“foo instanceof Foo”的值為true。把變量foo強制轉換為Foo類型是合法的:
            (Foo) foo //合法
            2.每個動態代理類實例都和一個InvocationHandler 實例關聯。Proxy 類的getInvocationHandler(Object proxy)靜態方法返回與參數proxy指定的代理類實例所關聯的InvocationHandler 對象。
            3.假定Foo接口有一個amethod()方法,那么當程序調用動態代理類實例foo的amethod()方法時,該方法會調用與它關聯的InvocationHandler 對象的invoke()方法。
            InvocationHandler 接口為方法調用接口,它聲明了負責調用任意一個方法的invoke()方法:
            Object invoke(Object proxy,Method method,Object[] args) throws Throwable
            參數proxy指定動態代理類實例,參數method指定被調用的方法,參數args 指定向被調用方法傳遞的參數,invoke()方法的返回值表示被調用方法的返回值。
            最后看一個例子,該例子模仿spring 的AOP原理。
          package proxy;
          import java.lang.reflect.InvocationHandler;
          import java.lang.reflect.Method;
          import java.lang.reflect.Proxy;
          class Logic{
          public void logic(){
          Dao dao = Factory.create();
          System.out.println("dynamic proxy's name: "+dao.getClass().getName());
          dao.insert();
          }
          }
          class Factory{
          static Dao create(){
          Dao dao = new JdbcDao();
          MyInvocationHandler hand = new MyInvocationHandler();
          return (Dao)hand.get(dao);
          }
          }
          interface Dao{
          public void update();
          public void insert();
          }
          class JdbcDao implements Dao{
          public void update(){
          System.out.println("in jdbc update");
          }
          public void insert(){
          System.out.println("in jdbc insert");
          }
          }
          class HibernateDao implements Dao{
          public void update(){
          System.out.println("in hibernate update");
          }
          public void insert(){
          System.out.println("in hibernate insert");
          }
          }
          class MyInvocationHandler implements InvocationHandler {
          Object o;
          public Object get(Object o){
          System.out.println("in get method of MyInvocationHandler");
          this.o = o;
          return Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),this);
          }
          public Object invoke(Object arg0, Method arg1, Object[] arg2)
          throws Throwable {
          System.out.println("write log before invoke");
          Object result = arg1.invoke(o, arg2);
          System.out.println("write log after invoke");
          return result;
          }
          }
          public class Test {
          public static void main(String[] args) {
          Logic l = new Logic();
          l.logic();
          }
          }
            運行結果:
            in get method of MyInvocationHandler
            dynamic proxy's name: proxy.$Proxy0
            write log before invoke
            in jdbc insert
            write log after invoke
            結論: JDK的動態代理并不能隨心所欲的代理所有的類。Proxy.newProxyInstance方法的第二個參數只能是接口數組, 也就是Proxy只能代理接口。

          posted on 2014-08-05 10:01 順其自然EVO 閱讀(207) 評論(0)  編輯  收藏 所屬分類: 測試學習專欄

          <2014年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 海淀区| 淮阳县| 邢台县| 承德市| 额尔古纳市| 阜阳市| 东乌珠穆沁旗| 武宣县| 青海省| 石家庄市| 长沙市| 安国市| 岢岚县| 集贤县| 辉县市| 红安县| 枣庄市| 五常市| 新沂市| 西贡区| 修水县| 苏尼特左旗| 宜阳县| 铁岭县| 中宁县| 韶关市| 祁阳县| 康保县| 安岳县| 杭锦旗| 黔西县| 涞源县| 株洲市| 镇远县| 颍上县| 汤阴县| 十堰市| 揭西县| 鄂尔多斯市| 东平县| 汕尾市|