java自定義classloader引發的思考


引用

classloader機制

  • 如下圖所示,java的classloader是雙親委派機制。會首先從父classloader加載指定的class,如果加載不到才會從子classloader中加載。
  • 主要這里的圖片主要用於體現classloader的父子關系,實際上實現時並不一定存在繼承關系。比如AppClassLoader的父classLoader是ExtClassLoader,但是實際實現時兩者都是繼承自URLClassLoader的。

自定義classloader

Animal類&包結構

  • 包結構如圖:

測試入口

  • 輸出結果如圖所示:

思考1

  • 我們定義的classloader真的被運行了嗎?
  • 實際上如果打一些日志或者是debug進去看下,會發現我們重寫的方法並沒有被執行,這是java classloader的委派機制搞的鬼,我們可以發現定制的TinglangClassLoader的父classloader為URLClassLoader,在URLClassLoader中就已經找到了Animal類了。
  • 所以這里可以重寫loadClass方法來保證我們的classLoader被執行。

思考2

  • 我們將代碼做一些變種,如下圖所示:
  • 執行結果直接拋異常了
  • 這是由於Animal類來源於兩個不同的類加載器。如果只是需要執行Animal中的say方法的話,直接反射調用即可,如下圖所示:

思考3

  • 我們再將代碼做一下變化,如下圖所示,Animal作為一個普通內部類來實現,如下圖所示:
  • 可以看到代碼已經提示無法實例化內部類了,這個是由於要實例化非靜態的內部類對象,必須要先實例化外部類的對象,可以采用下面的方法來解決:
  • ps:這里內部類有public修飾符~

思考4

  • tomcat也是定義了自己的classloader,那么為啥不用jvm提供的classloader呢?
  • 結合相關的資料主要是三個方面的目的:
    • webapp隔離:由於各個webapp中的class和lib文件需要相互隔離,不能出現一個應用中加載的類庫會影響到另一個應用的情況。
    • 安全性:與jvm相同,tomcat也期望使用單獨的classloader去裝載tomcat自身的類庫,以免其他惡意或者無意的破壞。
    • 熱部署:tomcat修改文件可以不用重啟自動裝載類庫,這個點后面我們會單獨抽取示例。

思考5

  • 既然ExtClassLoader是讀取特定目錄下的class文件,那么如果我將自定義的class文件移到$JAVA_HOME/jre/lib/ext/目錄下是不是就能夠達到指定classloader加載類的目標呢?
  • 這個點是可以的,但是必須要求是jar。

思考6

  • 類加載器常見的用途有類的隔離和熱替換,類的隔離非常好理解,那么熱替換呢?
  • 仍然以我們之前的代碼為例,如下圖所示:
  • 在程序運行過程中更新並編譯Animal類中say方法
  • 可以看到運行結果如圖所示:
  • ps:注意第一張圖中的紅色框框部分,如果修改為Thread.currentThread().getContextClassLoader()會發現實際上不會起作用,這是由於要想實現同一個類的不同版本的共存,這些不同的版本必須由不同的類加載器進行加載,因此就不能把這些類的加載工作委托給類加載器來完成,因為它們只有一份。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM