Spring學習第二天Aop_invoke的代理對象生成解析

我還是事先聲明我目前寫的都是我的一些理解,僅僅作爲我的筆記作爲參考!

今天的主要內容就是解析動態代理中的newProxyInstance 和 invoke方法

第一部分:newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h):這個方法主要就是獲取代理對象,其實就是委託類的實例,再進一步就是委託類擁有真實業務類的引用,從而這個代理類可以代替真實業務類處理業務邏輯;

    ClassLoader:類加載器的作用是什麼呢?顧名思義,就是加載類文件,就是.class字節碼文件(主要由8位字節碼組成),這個部分可以詳細的去學習JVM虛擬機;我的通俗理解就是使用這個類加載器對象可以去加載類對象;

    Class<?>[]:類,這個類是有一個private的私有構造方法,它是由JVM進行實例化的,大概所有的類都可以作爲它的實例,比如User.class,可以是它的一個實例,這個Class的組成呢? 我們通過一些元或者初始化的東西來描述一個類:

        包名、類名或者接口、修飾符(類的修飾符、接口的修飾符、屬性的修飾符、方法的修飾符)、

        方法以及方法參數、成員屬性、

        註解等等;

    InvocationHandler:顧名思義: 調用處理器接口,只有一個invoke的方法;

第二部分:invoke(target,args)方法:

    target: 方法名

    args: 傳入方法名中的參數

    綜合上面的因素:我們推斷: jvm的類加載器加載某一個類(真實業務類),因爲加載了這個類所以我們就可以獲得這個類的所有的信息(方法、屬性啊),然後通過指定方法(這個類中的特定業務邏輯方法)以及參數就可以進行調用了;

其實還是沒有理解到代理對象如何執行到業務方法的?然後我想理解的是invoke這個方法的底層:

  1. Object newProxyInstance(ClassLoader loader,  
  2.                       Class<?>[] interfaces,  
  3.                       InvocationHandler h) 

首先我們看下這個方法的實現:在獲得代理實例方法裏面有下面這個方法:

     Class cl = getProxyClass(loader, interfaces);//這個方法主要就是獲得代理的真實的類的對象,這個真實的類實現了至少一個接口,這個接口主要是我們自定義的(業務邏輯抽象接口),

  1. / 加載目標類實現的接口到內存中  
  2.         interfaceClass = Class.forName(interfaceName, false, loader);  

加載相應的接口到內存中,其實也就是加載.class文件中的Class對象到內存中,

  1. // 把目標類實現的接口名稱作爲緩存(Map)中的key  
  2.     Object key = Arrays.asList(interfaceNames);  
這幾個步驟是將第一次生成的Class類中的信息緩存起來,就是存到內存中,下次用的時候直接取,

  1. Map cache;  
  2.       
  3.     synchronized (loaderToCache) {  
  4.         // 從緩存中獲取cache  
  5.         cache = (Map) loaderToCache.get(loader);  
  6.         if (cache == null) {  
  7.         // 如果獲取不到,則新建地個HashMap實例  
  8.         cache = new HashMap();  
  9.         // 把HashMap實例和當前加載器放到緩存中  
  10.         loaderToCache.put(loader, cache);  
  11.         }  

最關鍵的是這個一步:

  1. try {  
  2.         // 中間省略了一些代碼 .......  
  3.           
  4.         // 這裏就是動態生成代理對象的最關鍵的地方  
  5.         byte[] proxyClassFile = ProxyGenerator.generateProxyClass(  
  6.             proxyName, interfaces);  
  7.         try {  
  8.             // 根據代理類的字節碼生成代理類的實例  
  9.             proxyClass = defineClass0(loader, proxyName,  
  10.             proxyClassFile, 0, proxyClassFile.length);  
  11.         } catch (ClassFormatError e) {  
  12.             throw new IllegalArgumentException(e.toString());  
  13.         }  
  14.         }  
  15.         // add to set of all generated proxy classes, for isProxyClass  
  16.         proxyClasses.put(proxyClass, null);  
  17.   
  18.     }   

我們是通過代理生成器來生成代理類的字節碼,(注意代理類是含有真實業務的類的引用的),

又當我們獲取到一個類的字節碼的時候,有一個方法可以直接獲取這個類的實例:

defineClass0(loader,proxyName,proxyClassFile,0,proxyClassFile.length);




    




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章