熱部署和熱載入是類似的,都是在不重新啟動Tomcat的情況下,使得應用的最新程式碼生效。
熱部署表示重新部署應用,它的執行主體是Host,表示主機。
熱載入表示重新載入class,它的執行主體是Context,表示應用。
熱部署和熱載入都需要監聽相應的檔案或資料夾是否發生了變化。它們都是由Tomcat的後臺執行緒觸發的。
BackgroundProcessor就表示後臺執行緒。
每個容器都可以擁有一個BackgroundProcessor,但是預設情況下只有Engine容器會在啟動的時候啟動一個BackgroundProcessor執行緒。
該執行緒會每隔一段時間(可以設定,單位為秒),去執行後臺任務,先執行本容器定義的後臺任務,然後再執行子容器的定義的後臺任務,子容器的任務執行完成後會繼續執行其子容器的任務,直到沒有子容器為止。從這裡可以看出就算每個容器自己開啟一個BackgroundProcessor,也只不過是多了一個執行相同任務的執行緒而已,執行任務的效率有所提升。
對於後臺任務,所有容器會有一些統一的任務需要執行:
1. 叢集伺服器心跳
2. 如果一個容器擁有自己的類載入器,那麼檢視是否需要進行熱載入
3. 檢查Session是否過期
4. 執行每個容器對於的Realm對應的後臺任務
5. 執行每個容器中pipeline中的每個valve的後臺任務
6. 釋出PERIODIC_EVENT事件
在這個過程中的第2步中會觸發熱載入,第6步中會觸發熱部署
我們可以在Context上設定reloadable屬性為true,這樣就表示該應用開啟了熱載入功能,預設是false。
熱載入觸發的條件是:WEB-INF/classes目錄下的檔案發生了變化,WEB-INF/lib目錄下的jar包新增、刪除、修改都會觸發熱載入。
熱載入大致流程為:
1. 設定當前Context不能接受以及處理請求標誌為true
2. 停止當前Context
3. 啟動當前Context
4. 設定當前Context不能接受以及處理請求標誌為false
我們著重來分析一下第2、3步。
我們不妨先來分析第3步-啟動當前Context的過程中會發生什麼事情:
這是第3步,我們在來看第2步:
對於第2步-停止當前Context,其實所做的事情比較單一,就是清空和銷燬,而其中跟類載入相關就是清空上文中的快取物件。
這樣,我們的熱載入就是先清空所有東西,然後重新啟動我們應用,但是因為這個的觸發條件基本上是class類發生了變化,所以熱載入的過程中關於應用其他的一些屬性是沒有發生變化的,比如你現在想在Context中新增一個Vavle是不會觸發熱載入的,而如果要達到這個效果就要用到熱部署。
注意:雖然我們在熱載入的過程發現它是先停止再啟動,做法看似粗暴,但是這樣是價效比比較高的,並且這種方式至少比重新啟動Tomcat效率要高很多。
注意:熱載入不能用於war包
關於類的載入,這裡有一點是需要注意的,對於一個class檔案所表示的類,同一個類載入器的不同範例,都可以載入這個類,並且得到的class物件是不同的,回到熱載入,我們舉一個例子,我們現在有一個A類,一個自定義的WebappClassloader類,一開始先用一個WebappClassloader範例載入A類,那麼在jvm中就會存在一個A類的class物件,然後進行熱載入,先停止,再啟動,在停止的時候會殺掉當前應用的所有執行緒(除開真正執行程式碼的執行緒),再啟動時又會生成一個WebappClassloader範例來載入A類,如果熱載入之前的那個A類的class物件還沒有被回收的話,那麼此時jvm中其實會存在兩個A類的class物件,這是不衝突,因為class物件的唯一標誌是類載入器範例物件+類的全限定名。
BackgroundProcessor執行緒第六步會發出一個PERIODIC_EVENT事件,而HostConfig監聽了此事件,當接收到此事件後就會執行熱部署的檢查與操作。
對於一個資料夾部署的應用,通常會檢查以下資源是否發生變動:
/tomcat-7/webapps/應用名.war
/tomcat-7/webapps/應用名
/tomcat-7/webapps/應用名/META-INF/context.xml
/tomcat-7/conf/Catalina/localhost/應用名.xml
/tomcat-7/conf/context.xml
對於一個War部署的應用,會檢查以下資源是否發生變動:
/tomcat-7/webapps/應用名.war
/tomcat-7/conf/Catalina/localhost/應用名.xml
/tomcat-7/conf/context.xml
對於一個描述符部署的應用,會檢查以下資源是否發生變動:
/tomcat-7/conf/Catalina/localhost/應用名.xml
指定的DocBase目錄
/tomcat-7/conf/context.xml
一旦這些檔案或目錄發生了變化,就會觸發熱部署,當然熱部署也是有開關的,在Host上,預設是開啟的。這裡需要注意的是,對於一個目錄是否發生了變化,Tomcat只判斷了這個目錄的修改時間是否發生了變化,所以和熱載入是不衝突的,因為熱載入監聽的是WEB-INF/classes和WEB-INF/lib目錄,而熱部署監聽的是應用名那一層的目錄。
在講熱部署的過程之前,我們要先講一下應用部署的優先順序,對於一個應用,我們可以在四個地方進行定義:
server.xml中的context節點
/tomcat-7/conf/Catalina/localhost/應用名.xml
/tomcat-7/webapps/應用名.war
/tomcat-7/webapps/應用名
優先順序就是上面所列的順序,意思是同一個應用名,如果你在這個四個地方都設定了,那麼優先順序低的將不起作用。因為Tomcat在部署一個應用的時候,會先查一下這個應用名是否已經被部署過了。
如果發生改變的是資料夾,比如/tomcat-7/webapps/應用名,那麼不會做什麼事情,只是會更新一下記錄的修改時間,這是因為這個/tomcat-7/webapps/應用名目錄下的檔案,要麼是jsp檔案,要麼是其他檔案,而Tomcat只會管jsp檔案,而對於jsp檔案如果發生了修改,jsp自帶的機制會處理修改的。
如果發生改變的是/tomcat-7/conf/Catalina/localhost/應用名.xml檔案,那麼就是先undeploy,然後再deploy,和熱載入其實類似。對於undeploy就不多說了,就是講當前應用從host從移除,這就包括了當前應用的停止和銷燬,然後還會從已部署列表中移除當前應用,然後呼叫deployApps()就可以重新部署應用了。
如果對於文章中有疑問歡迎在留言區進行提問,博主看到會及時解答。如果本文對你有幫助,請點個三連支援吧!