首先來看看 JAVA 熱部署與熱載入的聯繫: 1. 都可以不重啟伺服器的情況下進行編譯/部署項目; 2. 基於 Java 的類載入器實現 熱部署與熱載入的區別: 熱部署在伺服器 運行時 重新部署項目 熱載入在運行時重新載入 class (位元組碼文件) 只載入重新修改後的類(class 文件) 熱部署 ...
首先來看看 JAVA 熱部署與熱載入的聯繫:
都可以不重啟伺服器的情況下進行編譯/部署項目;
基於 Java 的類載入器實現
熱部署與熱載入的區別:
- 熱部署在伺服器運行時重新部署項目
- 熱載入在運行時重新載入 class (位元組碼文件)
只載入重新修改後的類(class 文件) - 熱部署會重新載入整個應用
- 熱載入在運行時重新載入 class
可以理解為 JVM 啟動後會啟動一個後臺線程,定時來監控文件的時間戳,如果變化就將類重新載入 - 熱部署更多在生產環境下使用,熱載入多在開發環境下使用(熱載入無法記錄“熱載入執行的日誌”)
下麵再來說一下 JVM 載入類的相關知識點,位元組碼文件肯定是通過類載入器進行載入的,類載入一般可分為五個階段:
- 載入
找到類的靜態存儲結構,載入到虛擬機里然後轉化成方法區運行時的數據結構,生成 class 對象;
允許用戶自定義類載入器參與進來 - 驗證
確保位元組碼是安全的,不會對虛擬機造成危害,可以通過啟動參數來禁用一些驗證(不推薦) - 準備
確定記憶體佈局,初始化類變數(給變數賦初始值不會執行程式自定義的賦值操作) - 解析
將符號引用轉換為直接引用 - 初始化
這裡才是調用程式自定義的初始化代碼
關於初始化階段,Java 規定在遇到五個時機時立即進行初始化(當然前面的步驟已經執行完了的情況下),需要註意的點有:
- 遇到了 new、get、static 這幾個位元組碼指令時如果類沒有初始化,則需要觸發初始化。
- final 修飾的類會在編譯時把結果放到常量池中,即使調用也不會觸發初始化。畢竟 final 關鍵字它修飾的是常量。
- 使用反射對類進行反射調用,如果類沒有進行初始化,就需要先初始化。
- 當初始化一個類的時候,如果發現其父類還沒有進行過初始化,需要先觸發父類的初始化。
也就是先初始化父類,再初始化子類。 - 虛擬機啟動的時候用戶需要制定一個要執行的主類,虛擬機會先初始化這個主類。
- 使用 jdk1.7 動態機制相關的句柄會進行初始化。
Java 類載入器的特點:
- 由 APPClass Loader (系統類載入器)開始載入指定的類。
- 類載入器將載入任務交給其父,如果其父找不到,再由自己去載入。
- BootStrap Loader (啟動類載入器)是最頂級的類載入器,也就是說他的父載入器為空。
Java 類的熱部署可分為 類的熱載入 和 配置 Tomcat 的方式,配置 Tomcat 應該很熟悉了,關於類的熱載入相關代碼參考:
// 自定義的類載入器
public class MyClassLoader extends ClassLoader{
private String path;
public MyClassLoader(String path){
super(ClassLoader.getSystemClassLoader());
this.path = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException{
System.out.println("載入類.....");
byte[] data = loadClassData(name);
return this.defineClass(name,data,0,data.length);
}
// 載入 Class 文件中的內容
private byte[] loadClassData(String name){
try{
name = name.replace(".", "//");
FileInputStream is = new FileInputStream(new File(path + name + ".class"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = 0;
while((b = is.read()) != -1){
baos.write(b);
}
is.close();
return baos.toByteArray();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
對於Tomcat 直接把項目放到 webapps 目錄里就會自動載入;server.xml 里的 host 添加 context
SpringBoot
使用 SpringBoot 進行熱部署總體來說有兩種方式,
一種是使用 springloaded(依賴配置在 build 中的 spring-boot-maven-plugin 插件中),必須要使用 mvn spring-boot:run
來允許才有效果,或者下載這個 jar 在 JVM 的啟動參數里配置。
第二種就比較簡單了,直接和平常一樣加入一個 devtools 依賴就可以了:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
是的,就是這麼簡單,推薦使用第二種
發佈
SpringBoot 項目可以使用 jar 包來直接運行,也可以發佈為 war 丟到 tomcat 里去允許,
第一種就不用多說了,運行 maven 的 install 後,直接命令行啟動就行:java -jar xxx.jar
第二種,首先打包方式改為 war 包,然後增加一個,然後在 application 入口類繼承 SpringBootServletInitializer,覆寫 configure 方法:
// @SpringBootApplication:Spring Boot項目的核心註解,主要目的是開啟自動配置
@SpringBootApplication
public class FirstSpringBootApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder){
return builder.sources(FirstSpringBootApplication.class);
}
public static void main(String[] args) {
// 啟動 SpringBoot 所必須的入口
SpringApplication.run(FirstSpringBootApplication.class, args);
}
}
需要加入的依賴,SpringBoot 中加依賴不需要指定版本,在父工程已經設置好了,並且名稱都是 spring-boot-* :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
然後執行 maven install
得到 war 包就可以了
參考自慕課網課程:
https://www.imooc.com/learn/915