Java_動態從新加載Class機制

Java動態從新加載Class 

    項目中使用到了動態從新加載Class的機制,做用是讓一些代碼上線以前能夠在線上環境測試一下,固然,這是很是很差的測試機制,我剛來的時候也爲這種機制感到驚訝—怎麼能夠在線上環境運行測試代碼!後來通過了解,這麼作的緣由有如下兩個: html

  • 有些代碼沒有辦法在本地進行測試,本地沒有線上的環境
  • 咱們弱到連測試機都沒有(這是重點)


    既然咱們連測試機都沒有,那麼我就以爲咱們的項目其實也沒有想象中的重要,這麼測就這麼測吧~~ 
    以前對ClassLoader沒啥概念,google到一篇文章,翻譯了一下而且作了一些補充,加深記憶 
原文地址: java

引用
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html#classloader


--------------------------------------------------- 
ClassLoader 
    顧名思義,ClassLoader就是用來Load Class的,當一個Class被加載的時候,這個Class所引用到的全部Class也會被加載,並且這種加載是遞歸的,也就是說,若是A引用到B,B 引用到C,那麼當A被加載的時候,B也會被加載,而B被加載的時候,C也會加載。如此遞歸直到全部須要的Class都加載好。 
    常見的ClassLoader: 測試

引用
* Bootstrap class loader:虛擬機運行時必需要用到的類的加載器,好比java.*。它一般是在虛擬機種用本地代碼(如C)實現,在系統中用null表示。 
* Extension class loader:負責加載ext目錄下的Class。 
* Application class loader:負責加載CLASSPATH上的類。



ClassLoader的代理層次關係 
    ClassLoader是以層次關係組織起來的,當你建立一個標準的Java ClassLoader的時候,你必須提供一個父ClassLoader。當一個ClassLoader須要加載一個Class的時候,它首先會讓父 ClassLoader去加載這個Class,若是父ClassLoader不能加載這個Class,那麼當前的ClassLoader纔會本身去加載。 
    ClassLoader加載Class的步驟: google

  • 檢查這個Class是否已經被加載過了
  • 若是沒有被加載過,那麼讓父ClassLoader嘗試去加載
  • 若是父ClassLoader沒法加載,那麼嘗試使用當前ClassLoader加載


    從ClassLoader加載Class的步驟能夠得知,若是你須要動態從新加載一個Class,那麼你的ClassLoader必須跟上述標準流程有所區別,須要動態加載的Class不能交給父ClassLoader,不然你本身的ClassLoader將沒有機會去加載這個Class(由於正常狀況下父ClassLoader老是能加載到你所請求的Class)。 
    因此,若是你須要ClassLoader從新加載一個Class,重寫findClass方法是起不到效果的,由於findClass在父 ClassLoader加載失敗以後纔會執行 spa

Java代碼   收藏代碼
  1. // First, check if the class has already been loaded  
  2.         Class c = findLoadedClass(name);  
  3.         if (c == null) {  
  4.         try {  
  5.         if (parent != null) {  
  6.             c = parent.loadClass(name, false);  
  7.         } else {  
  8.             c = findBootstrapClass0(name);  
  9.         }  
  10.         } catch (ClassNotFoundException e) {  
  11.             // If still not found, then invoke findClass in order  
  12.             // to find the class.  
  13.             c = findClass(name);  
  14.         }  
  15.     }  


    必須重寫loadClass方法才能達到效果。 

動態從新加載Class 
    Java內置的ClassLoader總會在加載一個Class以前檢查這個Class是否已經被加載過,已經被加載過的Class不會加載第二次。所以要想從新加載Class,咱們須要實現本身的ClassLoader。 
    另一個問題是,每一個被加載的Class都須要被連接(link),這是經過執行ClassLoader.resolve()來實現的,這個方法是 final的,所以沒法重寫。Resove()方法不容許一個ClassLoader實例link一個Class兩次,所以,當你須要從新加載一個 Class的時候,你須要從新New一個你本身的ClassLoader實例。 
    剛纔說到一個Class不能被一個ClassLoader實例加載兩次,可是能夠被不一樣的ClassLoader實例加載,這會帶來新的問題: 翻譯

Java代碼   收藏代碼
  1. MyObject object = (MyObject)  
  2.     myClassReloadingFactory.newInstance("com.jenkov.MyObject");  


這段代碼會致使一個ClassCastException,由於在一個Java應用中,Class是根據它的全名(包名+類名)和加載它的 ClassLoader來惟一標識的。在上面的代碼中object對象對應的Class和newInstance返回的實例對應的Class是有區別的: 代理

  全名 ClassLoader實例
Object對象的Class com.jenkov.MyObject  AppClassLoader實例
newInstance返回對象的Class com.jenkov.MyObject 自定義ClassLoader實例



    解決的辦法是使用接口或者父類,只從新加載實現類或者子類便可。 code

Java代碼   收藏代碼
  1. MyObjectInterface object = (MyObjectInterface)  
  2.     myClassReloadingFactory.newInstance("com.jenkov.MyObject");  
  3.   
  4. MyObjectSuperclass object = ( MyObjectSuperclass)  
  5.     myClassReloadingFactory.newInstance("com.jenkov.MyObject");  



    在本身實現的ClassLoader中,當須要加載MyObjectInterface或者MyObjectSuperclass的時候,要代理給父 ClassLoader去加載。 htm

相關文章
相關標籤/搜索