少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          java動態代理和cglib動態代理在工作中用代理的地方非常多,但一直還沒仔細來看代理的原理,今天被同事提到,所以自己開始仔細研究了一下這兩者代理都做了些什么工作,并通過編寫測試用例的方式來對兩種代理原理作理解。
          在自行看代碼之前,初步問了一下朋友,大概解釋這兩者區別是,java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。這是朋友說的,我并沒自己實驗過,所以也沒映象,所以開始自己動手實踐之:
          java動態代理

          使用方法:

          接口:

          public interface Call {
          void doCall(String doCall);
          }

          public interface Processor {
          void doProcess(String doProcess);
          }

          實現類:

          public class ServiceImpl implements Call, Processor {

          public void doCall(String doCall) {
          System.out.println("doCall");
          }

          public void doProcess(String doProcess) {
          System.out.println("doProcess");
          }
          }

          具體代理Handler:

          public class ServiceHandler implements InvocationHandler {

          private Call callService;

          public ServiceHandler(Call callService) {
          this.callService = callService;
          }

          public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable {
          System.out.println("proxyMethod=" + method.getName());
          Object obj = method.invoke(this.callService, args);
          System.out.println("after invoke!");
          return obj;
          }

          }

          使用java動態代理:

          public class JdkProxyTest {   
          @Test
          public void testJdkProxy() {
          Call call = new ServiceImpl();
          ServiceHandler handler = new ServiceHandler(call);
          Call callProxy = (Call) Proxy.newProxyInstance(call.getClass().getClassLoader(),
          new Class[]{Call.class}, handler);
          callProxy.doCall("test");
          }
          }

          最終效果就是執行代理接口的doCall方法之前,該方法被ServiceHandler給處理了。

          通過查看java.lang.reflect.Proxy代碼,大致擬了一下它的實現原理:
          1. 取到new Class[]{Call.class}這里所有接口,通過Class.forName把接口類加載到JVM,放到內部Set里保存,把接口的完善名字保存,帶包名的接口名字,并以把這組接口名稱數組轉換成List作為key,用于下面生成代理類后保存到內部Map的key.也就是相當于這一組的接口名稱對應的一個生成的代理類
          2. 主要是從內存里找是否之前已經生成好了這同一組接口的代理類,如果有就直接拿出。這里第一次是需要新建立的,所以開始創建代理,首先檢查代理目標接口的訪問控制符是否是默認包級別的,如果是就需要給生成的代理類設置目標接口同樣的包名,才能默認訪問這種級別下的接口。如果這種有默認訪問控制標識符的目標接口,又有不同包名的目標接口,則會報出錯誤。否則其它情況,是給的無包名的代理類,生成的代理類的默認名稱是$Proxy開頭加Proxy里標識唯一類名的數字,是靜態long型變量,每次生成一次代理類會累加
          3. 調用ProxyGenerator.generateProxyClass(proxyName, interfaces)動態生成class字節碼類,該類相當于是Proxy的子類,實現了需要代理的接口方法,并在每個方法里調用了InvocationHandler的invoke方法,而我們自己實現的InvocationHandler接口類里完成了以反射方式最終對目標業務類的接口方法進行調用。所以此種方式實現的動態代理只能代理接口方法,對具體類的代理不能實現。

           

          http://hi.baidu.com/dobug/blog/item/493f817e802479340cd7dab9.html

          posted on 2012-06-07 21:51 abin 閱讀(709) 評論(0)  編輯  收藏 所屬分類: java基礎知識

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 土默特左旗| 会理县| 西乌| 天津市| 新源县| 瑞昌市| 沙湾县| 阿拉善盟| 西乌| 东山县| 六安市| 西华县| 鹤庆县| 容城县| 白沙| 平陆县| 丰台区| 任丘市| 宁陕县| 西昌市| 武鸣县| 阜南县| 普兰店市| 宁安市| 禄劝| 南溪县| 方山县| 深水埗区| 温宿县| 岳阳县| 济南市| 石泉县| 满洲里市| 北碚区| 富川| 海林市| 宜昌市| 永登县| 静海县| 张家口市| 阜南县|