目的
這是面試/工作中都能用到的知識,花幾分鐘的時間,通過精簡的代碼,帶你掌握java中熱加載的實現方式以及核心原理。(我是在看JVM類加載機制和Tomcat源碼的時候受到啟發)
準備工作
1、 在D:\\\\test-class\\\\目錄,寫一個類 HelloService.java
public class HelloService {
public String getValue() {
return "666";
}
}
2、 編譯
javac HelloService.java
現在我們在D:\\\\test-class\\\\目錄已經有了一個HelloService.class。
接下來,我們實現這個類的熱加載,每次更新這個代碼,都能不停機,自動加載最新代碼邏輯。
熱加載核心代碼
描述一下這段代碼運行的效果,運行之後,每隔1秒去加載最新的class文件,調用上述HelloService的getValue方法。不斷輸出
調用getValue獲得的返回值為:666
調用getValue獲得的返回值為:666
調用getValue獲得的返回值為:666
不要關閉這個程序,我們來測試熱加載
- 將HelloService.java中getValue方法的返回值修改為 【return "999";】
- javac 重新編譯 HelloService.java
- 編譯成功後,你應該會看到程序的控制檯輸出變為 “調用getValue獲得的返回值為:999”
- 如果輸出內容改變了,則代表熱加載成功。
是不是很神奇,接下來介紹一下原理
原理分解
1、 首要了解類加載器是什麼
我們的代碼由.java 編譯成 .class,要想在jvm中運行,需要被加載到JVM中。
而加載class的工作是有類加載器實例去實現的,類加載器支持通過文件目錄,jar,zip,網絡等多種途徑,加載class類文件。
JVM啟動後就默認有三個類加載器實例,負責去加載不同位置的class。
> 核心類庫加載器 BootStrap ClassLoader,負責加載jdk安裝目錄下lib文件夾裡面的jar包,我們的String.class,System.class這些類都放在這個目錄下面,啟動jvm就會去加載,必不可少。
> 拓展類庫加載器 Extension ClassLoader,負責加載jdk安裝目錄下lib/ext文件夾裡面的jar包,這裡面是一些jdk的拓展jar包,比如zipfs.jar這樣的包或工具類。拓展的意思就是在某些情況下,這些jar包不加載也不影響jvm工作。
> 應用程序代碼加載器 Application ClassLoader,負責加載我們自己寫的程序代碼,通過java命令 -cp 或者 -classpath告訴jvm我們的代碼class存放位置。如果我們的程序是jar包運行,你可以在jar包 META-INF目錄MANIFEST.MF文件裡面看到一個Class-Path: .配置,這就是指定代碼位置的。
2、 熱加載
java中有這麼一個概念“同一個類名,同一個類加載器實例加載的,代表是同一個類”。
如果我們要自己實現業務代碼的熱加載,就不能用默認的類加載器實例,因為同一個類加載器實例加載一次後會存起來,後面的class文件就算更新了也不會再次加載了。
我們需要自己創建類加載器實例,告訴它我們要加載的class文件位置。我上面的代碼中每隔一秒創建一個URLClassLoader類加載器實例對象,用這個新的類加載器實例去加載修改後的class,所以jvm會認為這是一個新的類,從而實現了熱更新。
這就是利用了JVM類加載機制實現的熱加載,比如Tomcat中jsp熱更新就是這樣實現的。
你懂了嘛?有什麼想法可以留言交流哦!
閱讀更多 JAVA老油條 的文章