<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          java動(dòng)態(tài)代理底層探究

          共 11554字,需瀏覽 24分鐘

           ·

          2021-03-26 08:37

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          平常面試的時(shí)候,有人回問(wèn)你Spring,你會(huì)說(shuō)什么AOP什么的,然后他會(huì)越來(lái)越往深問(wèn),其實(shí)說(shuō)到AOP那么動(dòng)態(tài)代理是繞不開(kāi)的,那么今天我們一起來(lái)看看這個(gè)動(dòng)態(tài)代理是什么個(gè)一回事先貼一張圖:

          上面便是動(dòng)態(tài)代理的結(jié)束以及它的實(shí)現(xiàn)方式,以及區(qū)別(我確實(shí)很懶....)but 上面的也挺通俗易懂,只要你不是初學(xué)者


          -----------------------------------------華麗的分割線----------------------------------------


          接下來(lái)當(dāng)然要繼續(xù)貼圖啦:



          這張圖便是動(dòng)態(tài)代理大概的實(shí)現(xiàn)流程,我們看到.只有javaProxy是直接修改字節(jié)碼的,其他的都是基于ASM來(lái)操作字節(jié)碼ASM我也不太懂,然后那個(gè)javassist也是用來(lái)操作ASM的,是島國(guó)一位工程師寫(xiě)的,據(jù)說(shuō)dubbo就是用的這項(xiàng)技術(shù).


          我們看到無(wú)論是何種方式它都是基于對(duì)class字節(jié)碼的修改來(lái)進(jìn)行代理的.

          好的這只是一個(gè)大概的了解那么我們來(lái)寫(xiě)代碼感受感受:


          整體需求就是一個(gè)普通的Service接口,


          讓后一個(gè)普通的實(shí)現(xiàn)類,ServiceImpl 


          最后我們來(lái)個(gè)測(cè)試的小方法:來(lái)看看動(dòng)態(tài)代理的實(shí)現(xiàn):

          public class ProjexTest {
              public static void main(String[] args) {
                  final  serviceImpl impl =new serviceImpl();
                  UserServce  servce = (UserServce)Proxy.newProxyInstance(ProjexTest.class.getClassLoader(), new Class[]{UserServce.class}, new InvocationHandler() {
                      @Override
                      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                          System.out.println("代理執(zhí)行前");
                          try {
                              return method.invoke(impl, args);
                          } finally {
                              System.out.println("代理執(zhí)行后");
                          }
                      }
                  });
                  servce.get();
              }

          我們還是很奇怪上面到底是什么東東?用我表達(dá)不好語(yǔ)言解釋一下:


          首先,我們new 了一個(gè)newProxyInstance()然后我們?cè)贗nvocationHandler()里面的invoke方法來(lái)實(shí)現(xiàn)它的動(dòng)態(tài)代理.

          還是貼圖方便一點(diǎn)這樣我們便實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的代理類


          這里的我們get()方法就相當(dāng)于客戶端,掉的是userservice接口的方法,委托類就是serviceimpl 代理類就是我們傳的userservice.class,這樣通過(guò)接口屏蔽的底層的實(shí)現(xiàn)細(xì)節(jié),這樣透明化嘍.



          對(duì)啊是如何做到代理目標(biāo)對(duì)象的呢?這個(gè)好說(shuō)我們通過(guò)代理類來(lái)分析一下:

          @Test
          public void buildProcyClass() throws IOException {
              byte[] bytes = ProxyGenerator.generateProxyClass("UserService$proxy", new Class[]{
                      UserServce.class
              });
              String filename = String.format("%s/target/UserService$proxy.class", System.getProperty("user.dir"));
              File file = new File(filename);
              FileOutputStream outputStream = new FileOutputStream(file);
              outputStream.write(bytes);
              outputStream.flush();
              outputStream.close();
          }

          這樣我就把它代理的類輸出出來(lái)了:

          public final class UserService$proxy extends Proxy implements UserServce {
              private static Method m1;
              private static Method m2;
              private static Method m3;
              private static Method m0;

              public UserService$proxy(InvocationHandler var1) throws  {
                  super(var1);
              }

              public final boolean equals(Object var1) throws  {
                  try {
                      return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
                  } catch (RuntimeException | Error var3) {
                      throw var3;
                  } catch (Throwable var4) {
                      throw new UndeclaredThrowableException(var4);
                  }
              }

              public final String toString() throws  {
                  try {
                      return (String)super.h.invoke(this, m2, (Object[])null);
                  } catch (RuntimeException | Error var2) {
                      throw var2;
                  } catch (Throwable var3) {
                      throw new UndeclaredThrowableException(var3);
                  }
              }

              public final String get() throws  {
                  try {
                      return (String)super.h.invoke(this, m3, (Object[])null);
                  } catch (RuntimeException | Error var2) {
                      throw var2;
                  } catch (Throwable var3) {
                      throw new UndeclaredThrowableException(var3);
                  }
              }

              public final int hashCode() throws  {
                  try {
                      return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
                  } catch (RuntimeException | Error var2) {
                      throw var2;
                  } catch (Throwable var3) {
                      throw new UndeclaredThrowableException(var3);
                  }
              }

              static {
                  try {
                      m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                      m2 = Class.forName("java.lang.Object").getMethod("toString");
                      m3 = Class.forName("com.yqun.springboot.service.UserServce").getMethod("get");
                      m0 = Class.forName("java.lang.Object").getMethod("hashCode");
                  } catch (NoSuchMethodException var2) {
                      throw new NoSuchMethodError(var2.getMessage());
                  } catch (ClassNotFoundException var3) {
                      throw new NoClassDefFoundError(var3.getMessage());
                  }
              }

          這個(gè)就是輸出來(lái)的類,我們可以看到代理過(guò)來(lái)的類:


          return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); 里面的參數(shù)就對(duì)應(yīng)著:


           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 上問(wèn)中這個(gè)invoke里面要的參數(shù),


          其實(shí)這樣我們可以清楚的看到,代理類回事怎么一回事


          我們看看他是怎么生成的:追 類 可以通過(guò)了嗎看到它就是生成一個(gè)動(dòng)態(tài)代理對(duì)對(duì)象

          public static Object newProxyInstance(ClassLoader loader,
                                                Class<?>[] interfaces,
                                                InvocationHandler h)
          /*獲取查詢遍歷已經(jīng)構(gòu)建好的class類也就是我們接口的代理類
           * Look up or generate the designated proxy class.
           */
          Class<?> cl = getProxyClass0(loader, intfs);
          // If the proxy class defined by the given loader implementing //點(diǎn)進(jìn)去首先會(huì)通過(guò)從load緩存里面取
          // the given interfaces exists, this will simply return the cached copy;//如果有對(duì)它從字節(jié)碼進(jìn)行構(gòu)建
          // otherwise, it will create the proxy class via the ProxyClassFactory//沒(méi)有的話去創(chuàng)建一個(gè)新的
          return proxyClassCache.get(loader, interfaces);

          我們看到如果它沒(méi)有的話回去ProxyClassFactory類里面去實(shí)現(xiàn)那么我們就看看里面的方法,


           -->ProxyClassFactory.apply 就是裝配自動(dòng)代理的過(guò)程 動(dòng)態(tài)代理所用的接口

                  public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

           //存儲(chǔ)所有動(dòng)態(tài)代理所對(duì)應(yīng)的接口

                      Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);

                      for (Class<?> intf : interfaces) {

                          /*驗(yàn)證接口 也就是說(shuō)ClassLoader 對(duì)應(yīng)的接口是否已經(jīng)存在是否是同一個(gè)

                           * Verify that the class loader resolves the name of this

                           * interface to the same Class object.


                           */


          也就是說(shuō)對(duì)代理的類是不service的實(shí)現(xiàn)類


          當(dāng)然里面還有許多亂七八糟的方法,但是我只看懂了這個(gè).這里他會(huì)對(duì)字節(jié)碼重組也就是修改class文件,相當(dāng)于吧代碼編譯成字節(jié)碼


          在往深就是類加載器的方法了,這個(gè)便是對(duì)字節(jié)碼的重新裝載 也就是ClassLoad里面的

          @Deprecated
          protected final Class<?> defineClass(byte[] b, int off, int len)
              throws ClassFormatError
          {
              return defineClass(null, b, off, len, null);
          }

          的方法


          總結(jié)兩張圖結(jié)尾:


          最后一張圖特別重要,也就是寫(xiě)了這么長(zhǎng)時(shí)間的總計(jì)吧算是...



          ————————————————

          版權(quán)聲明:本文為CSDN博主「一只想飛的豬豬」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。

          原文鏈接:

          https://blog.csdn.net/weixin_39715061/article/details/80394751





          鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布

          ??????

          ??長(zhǎng)按上方微信二維碼 2 秒





          感謝點(diǎn)贊支持下哈 

          瀏覽 58
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久激情亚洲色 | 夜夜爽天天操 | 大香蕉97 | 波多野结衣免费AV | 国产九色 |