Tomcat的熱部署和熱加載機制

Tomcat的熱部署和熱加載機制

說到tomcat的熱部署和熱加載,首先要明確什麼是熱部署?什麼是熱加載?

熱加載:實現方式是 Web 容器(Context組件)啓動一個後臺線程,定期檢測類文件的變化,如果有變化,就重新加載類,在這個
過程中不會清空 Session ,一般用在開發環境。

熱部署:署原理類似,也是由後臺線程定時檢測 Web 應用的
變化,但它會重新加載整個 Web 應用。這種方式會清空
Session,比熱加載更加乾淨、徹底,一般用在生產環

通過二者的定義,可以發現二者的實現都用到了Tomcat的後臺線程。首先要明確Container容器的子組件之間的關係結構如,如下所示:熱加載和熱部署的實現都離不開後臺線程的週期性檢查,Tomcat 在基類 ContainerBase 中統一實現了後臺線程的處理邏輯,並在頂層容器 Engine 啓動後臺線程。

  • Tomcat的後臺線程是怎麼實現的?
    Tomcat是通過ScheduledThreadPoolExecutor來啓動後臺線程的:
    根據上面的代碼可以看出,tomcat調用scheduleWithFixedDelay方法,傳入四個參數。
    最重要的是第一個參數:ContainerBackgroundProcessor(),它是一個 Runnable(Runnable是java實現多線程的接口,通過接口實現;與Threadl類似,只不過後者是實現多線程的類,通過繼承使用),同時也是 ContainerBase 的內部類,ContainerBase 是所有容器組件的基類,我們來回憶一下容器組件有哪些,有
    Engine、Host、Context 和 Wrapper 等,它們具有父子
    關係
    ContainerBackgroundProcessor的實現
    首先ContainerBackgroundProcessor 是一個 Runnable,它需要實現 run 方法,它的 run 很簡單,就是調用了processChildren 方法。這裏有個小技巧,它把“宿主類”,也就是ContainerBase 的類實例當成參數傳給了run 方法。而在 processChildren 方法裏,就做了兩步:調用當前容器的 backgroundProcess 方法,以及遞歸調用子孫的backgroundProcess 方法。請你注意backgroundProcess 是 Container 接口中的方法,也就是說所有類型的容器都可以實現這個方法,在這個方法裏完成需要週期性執行的任務。這樣的設計意味着什麼呢?我們只需要在頂層容器,也就是Engine 容器中啓動一個後臺線程,那麼這個線程不但會執行 Engine 容器的週期性任務,它還會執行所有子容器的週期性任務。
    backgroundProcess 方法
    上述代碼都是在基類 ContainerBase 中實現的,那具體容器類需要做什麼呢?其實很簡單,如果有週期性任務要執行,就實現 backgroundProcess 方法;如果沒有,就重用基類 ContainerBase 的方法。ContainerBase 的
    backgroundProcess 方法實現如下:
    有了 ContainerBase 中的後臺線程和backgroundProcess 方法,各種子容器和通用組件不需要
    各自弄一個後臺線程來處理週期性任務,這樣的設計顯得優雅和整潔
  • Tomcat是如何實現熱加載的?
    這個過程是在Context容器中實現的,Context容器的backgroundProcess方法是這樣實現的:
    從上面的代碼我們看到 Context 容器通過 WebappLoader來檢查類文件是否有更新,通過 Session 管理器來檢查是否有 Session 過期,並且通過資源管理器來檢查靜態資源是否有更新,最後還調用了父類 ContainerBase 的backgroundProcess 方法。
    這裏我們要重點關注,WebappLoader 是如何實現熱加載的,它主要是調用了 Context 容器的 reload 方法,而
    Context 的 reload 方法比較複雜,總結起來,主要完成了下面這些任務:
  1. 停止和銷燬 Context 容器及其所有子容器,子容器其實
    就是 Wrapper,也就是說 Wrapper 裏面 Servlet 實例也
    被銷燬了。
  2. 停止和銷燬 Context 容器關聯的 Listener 和 Filter。
  3. 停止和銷燬 Context 下的 Pipeline 和各種 Valve。
  4. 停止和銷燬 Context 的類加載器,以及類加載器加載的
    類文件資源。
  5. 啓動 Context 容器,在這個過程中會重新創建前面四步
    被銷燬的資源。
    在這個過程中,類加載器發揮着關鍵作用。一個 Context容器對應一個類加載器,類加載器在銷燬的過程中會把它加載的所有類也全部銷燬。Context 容器在啓動過程中,會創建一個新的類加載器來加載新的類文件。在 Context 的 reload 方法裏,並沒有調用 Session 管理器的 distroy 方法,也就是說這個 Context 關聯的 Session是沒有銷燬的。你還需要注意的是,Tomcat 的熱加載默認是關閉的,你需要在 conf 目錄下的 Context.xml 文件中設置 reloadable 參數來開啓這個功能,像下面這樣:
  • Tomcat是如何實現熱部署的?

    • 熱部署跟熱加載的本質區別是,熱部署會重新部署 Web 應用,原來的 Context 對象會整個被銷燬掉,因此這個 Context 所關聯的一切資源都會被銷燬,包括 Session。那麼 Tomcat 熱部署又是由哪個容器來實現的呢?應該不是由 Context,因爲熱部署過程中 Context 容器被銷燬了,那麼這個重擔就落在 Host 身上了,因爲它是 Context 的父容器。跟 Context 不一樣,Host 容器並沒有在backgroundProcess 方法中實現週期性檢測的任務,而是通過監聽器 HostConfig 來實現的,HostConfig 就是前面提到的“週期事件”的監聽器,那“週期事件”達到時,HostConfig 會做什麼事呢?
      它執行了 check 方法,我們接着來看 check 方法裏做了什麼?
      其實 HostConfig 會檢查 webapps 目錄下的所有 Web 應用:
      如果原來 Web 應用目錄被刪掉了,就把相應 Context 容器整個銷燬掉。是否有新的 Web 應用目錄放進來了,或者有新的 WAR包放進來了,就部署相應的 Web 應用。
      因此 HostConfig 做的事情都是比較“宏觀”的,它不會去檢查具體類文件或者資源文件是否有變化,而是檢查 Web應用目錄級別的變化。
  • 總結
    今天我們學習 Tomcat 的熱加載和熱部署,它們的目的都是在不重啓 Tomcat 的情況下實現 Web 應用的更新。
    熱加載的粒度比較小,主要是針對類文件的更新,通過創建新的類加載器來實現重新加載。而熱部署是針對整個 Web應用的,Tomcat 會將原來的 Context 對象整個銷燬掉,再重新創建 Context 容器對象。
    熱加載和熱部署的實現都離不開後臺線程的週期性檢查,Tomcat 在基類 ContainerBase 中統一實現了後臺線程的處理邏輯,並在頂層容器 Engine 啓動後臺線程,這樣子容器組件甚至各種通用組件都不需要自己去創建後臺線程,這樣的設計顯得優雅整潔。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章