Java動態從新加載Class
項目中使用到了動態從新加載Class的機制,做用是讓一些代碼上線以前能夠在線上環境測試一下,固然,這是很是很差的測試機制,我剛來的時候也爲這種機制感到驚訝—怎麼能夠在線上環境運行測試代碼!後來通過了解,這麼作的緣由有如下兩個: html
既然咱們連測試機都沒有,那麼我就以爲咱們的項目其實也沒有想象中的重要,這麼測就這麼測吧~~
以前對ClassLoader沒啥概念,google到一篇文章,翻譯了一下而且作了一些補充,加深記憶
原文地址: java
---------------------------------------------------
ClassLoader
顧名思義,ClassLoader就是用來Load Class的,當一個Class被加載的時候,這個Class所引用到的全部Class也會被加載,並且這種加載是遞歸的,也就是說,若是A引用到B,B 引用到C,那麼當A被加載的時候,B也會被加載,而B被加載的時候,C也會加載。如此遞歸直到全部須要的Class都加載好。
常見的ClassLoader: 測試
ClassLoader的代理層次關係
ClassLoader是以層次關係組織起來的,當你建立一個標準的Java ClassLoader的時候,你必須提供一個父ClassLoader。當一個ClassLoader須要加載一個Class的時候,它首先會讓父 ClassLoader去加載這個Class,若是父ClassLoader不能加載這個Class,那麼當前的ClassLoader纔會本身去加載。
ClassLoader加載Class的步驟: google
從ClassLoader加載Class的步驟能夠得知,若是你須要動態從新加載一個Class,那麼你的ClassLoader必須跟上述標準流程有所區別,須要動態加載的Class不能交給父ClassLoader,不然你本身的ClassLoader將沒有機會去加載這個Class(由於正常狀況下父ClassLoader老是能加載到你所請求的Class)。
因此,若是你須要ClassLoader從新加載一個Class,重寫findClass方法是起不到效果的,由於findClass在父 ClassLoader加載失敗以後纔會執行 spa
必須重寫loadClass方法才能達到效果。
動態從新加載Class
Java內置的ClassLoader總會在加載一個Class以前檢查這個Class是否已經被加載過,已經被加載過的Class不會加載第二次。所以要想從新加載Class,咱們須要實現本身的ClassLoader。
另一個問題是,每一個被加載的Class都須要被連接(link),這是經過執行ClassLoader.resolve()來實現的,這個方法是 final的,所以沒法重寫。Resove()方法不容許一個ClassLoader實例link一個Class兩次,所以,當你須要從新加載一個 Class的時候,你須要從新New一個你本身的ClassLoader實例。
剛纔說到一個Class不能被一個ClassLoader實例加載兩次,可是能夠被不一樣的ClassLoader實例加載,這會帶來新的問題: 翻譯
這段代碼會致使一個ClassCastException,由於在一個Java應用中,Class是根據它的全名(包名+類名)和加載它的 ClassLoader來惟一標識的。在上面的代碼中object對象對應的Class和newInstance返回的實例對應的Class是有區別的: 代理
全名 | ClassLoader實例 | |
Object對象的Class | com.jenkov.MyObject | AppClassLoader實例 |
newInstance返回對象的Class | com.jenkov.MyObject | 自定義ClassLoader實例 |
解決的辦法是使用接口或者父類,只從新加載實現類或者子類便可。 code
在本身實現的ClassLoader中,當須要加載MyObjectInterface或者MyObjectSuperclass的時候,要代理給父 ClassLoader去加載。 htm