熱部署和熱加載是類似的,都是在不重啟Tomcat的情況下,使得應用的最新代碼生效,
熱部署表示重新部署應用,它的執行主體是Host,表示主機,
熱加載表示重新加載class,它的執行主體是Context,表示應用,
Tomcat中的后臺執行緒
熱部署和熱加載都需要監聽相應的檔案或檔案夾是否發生了變化,它們都是由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的程序中會發生什么事情:
- 創建一個每個應用都單獨自定義的WebappClassLoader
- 決議web.xml檔案,這一步會做很多事情,但是主要的目的是尋找定義的Servlet并把它添加到Context中去,而對于尋找Servlet需要進行兩個方面的尋找,一是從web.xml中尋找定義的Servlet,二是從尋找class檔案中添加了@WebServlet注解的類,大家很有可能認為,此時是不是會去加載我們定義的Servlet類,可以告訴大家的是,這個時候不會,Servlet類的加載是在后面步驟發生的,那么這里就有疑問了,我們要看一個類上是不是存在一個@WebServlet注解,應該要先加載這個類呀?Tomcat并沒有這么做,它是直接先把class檔案當做一個普通檔案,然后看這個檔案對應的地方是否存在一個WebServlet注解,如果存在,則認為這個class檔案是一個Servlet,然后把這個class的全名封裝到Servlet物件中去,然后將Servlet物件添加到Context物件中,在決議web.xml時也是類似了,對于我們定義的Servlet,最后都會生成一個Servlet物件,然后記錄一個這個Servlet物件對應的class的全名,最后把Servlet物件添加到Context中去,
- 我們在使用Servlet的時候還會用其他的一些注解比如@ServletSecurity、@RunAs等等,對于這些注解是有特定功能的,Tomcat為了識別這個注解,此時就要去真正加載我們的Servlet類了,當然要不要識別這些注解是可以配置的,如果不識別,那么這一步就不會發生了,那么Servlet類的加載就會在有請求過來時才會進行類的加載,
加載類程序:
- 呼叫WebappClassLoaderBase的loadClass方法進行類的加載,該方法傳遞一個類的全限定名,
- 要加載一個類,先得找到這個類在哪里,對應的是哪個classs檔案,所以Tomcat中有一個快取物件,該物件保存了一個類的全限定名對應的資源路徑,當然,在第一次加載這個類時,這個快取是空的,所以這個時候就要去尋找這個類對應的class檔案地址,找到之后再快取,接下來就來分析是怎么找到這個class檔案地址的,
- 其實查找很容易,現在WEB-INF/classes/目錄下是否存在這個類,如果不存在就看WEB-INF/lib/目錄下的JAR包中是否存在這個類,最終如果找到就將進行快取,保存一個類的全限定名對應的class檔案地址或jar包地址,
- 當知道這個類在哪了之后,就可以defineClass了,最終得到一個class物件,并且也會將這個class物件設定到我們的快取中,所以上文說的快取中,其實是這么一個映射關系,一個類的全限定名對應這個類的檔案地址以及這個類的class物件,
- 所以當下次再有情況需要加載class時,就可以直接取快取中的對應的class物件了,
這是第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()就可以重新部署應用了,
如果對于文章中有疑問歡迎在留言區進行提問,博主看到會及時解答,如果本文對你有幫助,請點個三連支持吧!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/185961.html
標籤:其他
下一篇:藍色版蘋果iPhone 12開箱上手視頻流出;谷歌回應司法部反壟斷訴訟:存在嚴重漏洞;?Git 2.29 穩定版發布|極客頭條
