qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請?jiān)L問 http://qaseven.github.io/

          Java 代理(proxy)模式

          代理模式(Proxy Pattern)
            代理模式是常用的Java 設(shè)計(jì)模式,它的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息等。代理類與委托類之間通常會(huì)存在關(guān)聯(lián)關(guān)系,一個(gè)代理類的對象與一個(gè)委托類的對象關(guān)聯(lián),代理類的對象本身并不真正實(shí)現(xiàn)服務(wù),而是通過調(diào)用委托類的對象的相關(guān)方法,來提供特定的服務(wù)。
            如下列子:
          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();
          }
          }
            運(yùn)行結(jié)果:
            write log before invoke
            in jdbc insert
            write log after invoke
            隨著Proxy的流行,Sun把它納入到JDK1.3實(shí)現(xiàn)了Java的動(dòng)態(tài)代理。動(dòng)態(tài)代理和普通的代理模式的區(qū)別,就是動(dòng)態(tài)代理中的代理類是由 java.lang.reflect.Proxy類在運(yùn)行期時(shí)根據(jù)接口定義,采用Java反射功能動(dòng)態(tài)生成的。和 java.lang.reflect.InvocationHandler結(jié)合,可以加強(qiáng)現(xiàn)有類的方法實(shí)現(xiàn)。如圖2,圖中的自定義Handler實(shí)現(xiàn) InvocationHandler接口,自定義Handler實(shí)例化時(shí),將實(shí)現(xiàn)類傳入自定義Handler對象。自定義Handler需要實(shí)現(xiàn) invoke方法,該方法可以使用Java反射調(diào)用實(shí)現(xiàn)類的實(shí)現(xiàn)的方法,同時(shí)當(dāng)然可以實(shí)現(xiàn)其他功能,例如在調(diào)用實(shí)現(xiàn)類方法前后加入Log。而Proxy類根據(jù)Handler和需要代理的接口動(dòng)態(tài)生成一個(gè)接口實(shí)現(xiàn)類的對象。當(dāng)用戶調(diào)用這個(gè)動(dòng)態(tài)生成的實(shí)現(xiàn)類時(shí),實(shí)際上是調(diào)用了自定義Handler的 invoke方法。
            Proxy類提供了創(chuàng)建動(dòng)態(tài)代理類及其實(shí)例的靜態(tài)方法。
            (1)getProxyClass()靜態(tài)方法負(fù)責(zé)創(chuàng)建動(dòng)態(tài)代理類,它的完整定義如下:
            public static Class<?> getProxyClass(ClassLoader loader, Class<?>[] interfaces) throws IllegalArgumentException
            參數(shù)loader 指定動(dòng)態(tài)代理類的類加載器,參數(shù)interfaces 指定動(dòng)態(tài)代理類需要實(shí)現(xiàn)的所有接口。
            (2)newProxyInstance()靜態(tài)方法負(fù)責(zé)創(chuàng)建動(dòng)態(tài)代理類的實(shí)例,它的完整定義如下:
            public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws
            IllegalArgumentException
            參數(shù)loader 指定動(dòng)態(tài)代理類的類加載器,參數(shù)interfaces 指定動(dòng)態(tài)代理類需要實(shí)現(xiàn)的所有接口,參數(shù)handler 指定與動(dòng)態(tài)代理類關(guān)聯(lián)的 InvocationHandler 對象。
            以下兩種方式都創(chuàng)建了實(shí)現(xiàn)Foo接口的動(dòng)態(tài)代理類的實(shí)例:
            /**** 方式一 ****/
            //創(chuàng)建InvocationHandler對象
            InvocationHandler handler = new MyInvocationHandler(...);
            //創(chuàng)建動(dòng)態(tài)代理類
            Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });
            //創(chuàng)建動(dòng)態(tài)代理類的實(shí)例
            Foo foo = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).
            newInstance(new Object[] { handler });
            /**** 方式二 ****/
            //創(chuàng)建InvocationHandler對象
            InvocationHandler handler = new MyInvocationHandler(...);
            //直接創(chuàng)建動(dòng)態(tài)代理類的實(shí)例
            Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] { Foo.class }, handler);
            由Proxy類的靜態(tài)方法創(chuàng)建的動(dòng)態(tài)代理類具有以下特點(diǎn):
            動(dòng)態(tài)代理類是public、final和非抽象類型的;
            動(dòng)態(tài)代理類繼承了java.lang.reflect.Proxy類;
            動(dòng)態(tài)代理類的名字以“$Proxy”開頭;
            動(dòng)態(tài)代理類實(shí)現(xiàn)getProxyClass()和newProxyInstance()方法中參數(shù)interfaces指定的所有接口;
            Proxy 類的isProxyClass(Class<?> cl)靜態(tài)方法可用來判斷參數(shù)指定的類是否為動(dòng)態(tài)代理類。只有通過Proxy類創(chuàng)建的類才是動(dòng)態(tài)代理類;
            動(dòng)態(tài)代理類都具有一個(gè)public 類型的構(gòu)造方法,該構(gòu)造方法有一個(gè)InvocationHandler 類型的參數(shù)。
            由Proxy類的靜態(tài)方法創(chuàng)建的動(dòng)態(tài)代理類的實(shí)例具有以下特點(diǎn):
            1. 假定變量foo 是一個(gè)動(dòng)態(tài)代理類的實(shí)例,并且這個(gè)動(dòng)態(tài)代理類實(shí)現(xiàn)了Foo 接口,那么“foo instanceof Foo”的值為true。把變量foo強(qiáng)制轉(zhuǎn)換為Foo類型是合法的:
            (Foo) foo //合法
            2.每個(gè)動(dòng)態(tài)代理類實(shí)例都和一個(gè)InvocationHandler 實(shí)例關(guān)聯(lián)。Proxy 類的getInvocationHandler(Object proxy)靜態(tài)方法返回與參數(shù)proxy指定的代理類實(shí)例所關(guān)聯(lián)的InvocationHandler 對象。
            3.假定Foo接口有一個(gè)amethod()方法,那么當(dāng)程序調(diào)用動(dòng)態(tài)代理類實(shí)例foo的amethod()方法時(shí),該方法會(huì)調(diào)用與它關(guān)聯(lián)的InvocationHandler 對象的invoke()方法。
            InvocationHandler 接口為方法調(diào)用接口,它聲明了負(fù)責(zé)調(diào)用任意一個(gè)方法的invoke()方法:
            Object invoke(Object proxy,Method method,Object[] args) throws Throwable
            參數(shù)proxy指定動(dòng)態(tài)代理類實(shí)例,參數(shù)method指定被調(diào)用的方法,參數(shù)args 指定向被調(diào)用方法傳遞的參數(shù),invoke()方法的返回值表示被調(diào)用方法的返回值。
            最后看一個(gè)例子,該例子模仿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();
          }
          }
            運(yùn)行結(jié)果:
            in get method of MyInvocationHandler
            dynamic proxy's name: proxy.$Proxy0
            write log before invoke
            in jdbc insert
            write log after invoke
            結(jié)論: JDK的動(dòng)態(tài)代理并不能隨心所欲的代理所有的類。Proxy.newProxyInstance方法的第二個(gè)參數(shù)只能是接口數(shù)組, 也就是Proxy只能代理接口。

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

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

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 赫章县| 灌阳县| 垦利县| 韶山市| 广南县| 聂拉木县| 万荣县| 苍南县| 彭泽县| 正蓝旗| 故城县| 柘城县| 兴仁县| 伊通| 偏关县| 乐陵市| 西林县| 惠水县| 南投县| 修武县| 邵东县| 南京市| 城步| 文登市| 常熟市| 阿克| 闽侯县| 广宗县| 江达县| 彝良县| 郑州市| 措勤县| 远安县| 探索| 竹山县| 县级市| 吉隆县| 乌苏市| 卫辉市| 霍山县| 平阴县|