1. 程式人生 > >圖解Tomcat類載入機制(阿里面試題)

圖解Tomcat類載入機制(阿里面試題)

Tomcat的類載入機制是違反了雙親委託原則的,對於一些未載入的非基礎類(Object,String等),各個web應用自己的類載入器(WebAppClassLoader)會優先載入,載入不到時再交給commonClassLoader走雙親委託。 

對於JVM來說:

因此,按照這個過程可以想到,如果同樣在CLASSPATH指定的目錄中和自己工作目錄中存放相同的class,會優先載入CLASSPATH目錄中的檔案。

 1、既然 Tomcat 不遵循雙親委派機制,那麼如果我自己定義一個惡意的HashMap,會不會有風險呢?(阿里的面試官問)

答: 顯然不會有風險,如果有,Tomcat都執行這麼多年了,那群Tomcat大神能不改進嗎? tomcat不遵循雙親委派機制,只是自定義的classLoader順序不同,但頂層還是相同的,

還是要去頂層請求classloader.

2、我們思考一下:Tomcat是個web容器, 那麼它要解決什麼問題: 1. 一個web容器可能需要部署兩個應用程式,不同的應用程式可能會依賴同一個第三方類庫的不同版本,不能要求同一個類庫在同一個伺服器只有一份,因此要保證每個應用程式的類庫都是獨立的,保證相互隔離。 2. 部署在同一個web容器中相同的類庫相同的版本可以共享。否則,如果伺服器有10個應用程式,那麼要有10份相同的類庫載入進虛擬機器,這是扯淡的。 3. web容器也有自己依賴的類庫,不能於應用程式的類庫混淆。基於安全考慮,應該讓容器的類庫和程式的類庫隔離開來。 4. web容器要支援jsp的修改,我們知道,jsp 檔案最終也是要編譯成class檔案才能在虛擬機器中執行,但程式執行後修改jsp已經是司空見慣的事情,否則要你何用? 所以,web容器需要支援 jsp 修改後不用重啟。

再看看我們的問題:Tomcat 如果使用預設的類載入機制行不行? 答案是不行的。為什麼?我們看,第一個問題,如果使用預設的類載入器機制,那麼是無法載入兩個相同類庫的不同版本的,預設的累加器是不管你是什麼版本的,只在乎你的全限定類名,並且只有一份。第二個問題,預設的類載入器是能夠實現的,因為他的職責就是保證唯一性。第三個問題和第一個問題一樣。我們再看第四個問題,我們想我們要怎麼實現jsp檔案的熱修改(樓主起的名字),jsp 檔案其實也就是class檔案,那麼如果修改了,但類名還是一樣,類載入器會直接取方法區中已經存在的,修改後的jsp是不會重新載入的。那麼怎麼辦呢?我們可以直接解除安裝掉這jsp檔案的類載入器,所以你應該想到了,每個jsp檔案對應一個唯一的類載入器,當一個jsp檔案修改了,就直接解除安裝這個jsp類載入器。重新建立類載入器,重新載入jsp檔案。

Tomcat 如何實現自己獨特的類載入機制?

所以,Tomcat 是怎麼實現的呢?牛逼的Tomcat團隊已經設計好了。我們看看他們的設計圖:

我們看到,前面3個類載入和預設的一致,CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebappClassLoader則是Tomcat自己定義的類載入器,它們分別載入/common/*/server/*/shared/*(在tomcat 6之後已經合併到根目錄下的lib目錄下)和/WebApp/WEB-INF/*中的Java類庫。其中WebApp類載入器和Jsp類載入器通常會存在多個例項,每一個Web應用程式對應一個WebApp類載入器,每一個JSP檔案對應一個Jsp類載入器。

  • commonLoader:Tomcat最基本的類載入器,載入路徑中的class可以被Tomcat容器本身以及各個Webapp訪問;
  • catalinaLoader:Tomcat容器私有的類載入器,載入路徑中的class對於Webapp不可見;
  • sharedLoader:各個Webapp共享的類載入器,載入路徑中的class對於所有Webapp可見,但是對於Tomcat容器不可見;
  • WebappClassLoader:各個Webapp私有的類載入器,載入路徑中的class只對當前Webapp可見;