這個問題的核心是classloader
上圖中 啟動類加載器,擴展類加載器,應用程序類加載器是 jvm 自帶的類加載器.
comm catalina shared webapp 是tomcat 擴展的加載器,他們分別加載 /common/*
、/server/*
、/shared/*
WebAppClassLoader 負載加載 webapp 目錄的jar 和 class .
WebAppClassLoader 沒有遵循雙親委托模式,他的具體加載邏輯如下:
第1步:檢查當前class loader 的緩存resourceEntries,是否已經加載,如果有直接返回。
第2步:檢查 jvm 自帶加載器是否加載過。
第3步:嘗試用 javaseClassLoader 去加載,為什么要做這個嘗試呢,防止代碼重寫了java.lang.String 等jdk核心類,從而導致異常。
第4步:如果設置了雙親委托模式 delegateLoad=true ,嘗試用父加載器加載。
第5步: 嘗試從當前classloader 制定的目錄中加載,同時會將加載信息放到緩存中 resourceEntries
這樣就實現了資源隔離。
擴展信息:
1.通過gc 回收class loader ,從而可以實現回收class,重新創建classloader,然后重新load class ,從而達到不重啟jvm更新class的目的(熱更新),jsp 的熱更新就是這么干的。
2. jvm instrumentation 機制可以通過agent,去修改正在運行中的已加載的class 對象,該方法很有用,比如生產環境出了問題,重啟后問題無法復現,那么就可以在線增加日志排錯.
阿里巴巴基於該原理開發了一個強大在線調試工具: https://github.com/alibaba/arthas
3. ClassFileTransformer 利用tranformer 和 class loader 可以實現很多很神奇的功能,比如所有controller 方法第一行打印出請求參數,實現這個目的可以用spring AOP,同時也可以用ClassFileTransformer。
groovy 通過大量的 ClassFileTransformer 修改了很多jdk 核心class 的方法.
相關資源:
1.https://blog.csdn.net/sdmjhca/article/details/77716899
2.https://www.cnblogs.com/aspirant/p/8991830.html