首先來看看 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 包就可以了
