Tomcat - 都說Tomcat違背了雙親委派機制,到底對不對?

      網友投稿 1240 2025-03-31

      文章目錄

      類加載的本質

      JVM 雙親委派機制

      BootstrapClassLoader(啟動類加載器)

      ExtensionClassLoader

      AppClassLoader

      Tomcat的 類加載順序

      Tomcat要解決什么問題?

      Tomcat違反了雙親委派機制?

      Tomcat加載機制小結

      Tomcat 熱加載JasperLoader

      常見錯誤

      NoClassDefFoundError

      NoSuchMethodError

      ClassCastException

      類加載的本質

      ClassLoader是用來加載 Class 的。它負責將 Class 的字節碼形式轉換成內存形式的 Class 對象。

      字節碼可以來自于磁盤文件 *.class,也可以是 jar 包里的 *.class,也可以來自遠程服務器提供的字節流,字節碼的本質就是一個字節數組 []byte,它有特定的復雜的內部格式。

      JVM 運行實例中會存在多個 ClassLoader,不同的 ClassLoader 會從不同的地方加載字節碼文件。

      它可以從不同的文件目錄加載,也可以從不同的 jar 文件中加載,也可以從網絡上不同的靜態文件服務器來下載字節碼再加載。

      JVM 雙親委派機制

      Java1.2之后引入雙親委派模式 。

      核心原理: 如果其中一個類加載器收到了類加載的請求,它并不會自己去加載而是會將該請求委托給父類的加載器去執行,如果父類加載器還存在父類加載器,則進一步向上委托,如此遞歸,請求最終到達頂層的啟動類加載器。

      如果父類能加載,則直接返回,如果父類加載不了則交由子類加載,這就是雙親委派模式。

      好處

      向上委托給父類加載,父類加載不了再自己加載

      避免重復加載,防止Java核心api被篡改

      BootstrapClassLoader(啟動類加載器)

      負責加載 JVM 運行時核心類,加載System.getProperty("sun.boot.class.path")所指定的路徑或jar

      ExtensionClassLoader

      負責加載 JVM 擴展類,比如 swing 系列、內置的 js 引擎、xml 解析器 等等,這些庫名通常以 javax 開頭,它們的 jar 包位于 JAVAHOME/lib/rt.jar文件中.

      加載System.getProperty("java.ext.dirs")所指定的路徑或jar。

      在使用Java運行程序時,也可以指定其搜索路徑,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld。

      AppClassLoader

      AppClassLoader才是直接面向我們用戶的加載器,它會加載 Classpath 環境變量里定義的路徑中的 jar 包和目錄。

      我們自己編寫的代碼以及使用的第三方 jar 包通常都是由它來加載的。

      加載System.getProperty("java.class.path")所指定的路徑或jar。

      在使用Java運行程序時,也可以加上-cp來覆蓋原有的Classpath設置,例如: java -cp ./lavasoft/classes HelloWorld

      Tomcat的 類加載順序

      在Tomcat中,默認的行為是先嘗試在Bootstrap和Extension中進行類型加載,如果加載不到則在WebappClassLoader中進行加載,如果還是找不到則在Common中進行查找 .

      Common是公共的包, tomcat可以外掛很多個webapps (tomcat和app分開部署) ,優先以webapps下的為主。

      tomcat7 —> 默認 WebappClassLoader 類加載器

      tomcat 8 ---->默認 ParallelWebappClassLoader 類加載器

      Tomcat要解決什么問題?

      作為一個Web容器,Tomcat要解決什么問題 , Tomcat 如果使用默認的雙親委派類加載機制能不能行?

      我們知道Tomcat可以部署多個應用,不同的應用程序可能會依賴同一個第三方類庫的不同版本,不能要求同一個類庫在同一個服務器只有一份,因此要保證每個應用程序的類庫都是獨立的,保證相互隔離 .

      舉個例子 假設APP1 使用的是 Spring4 , APP2 使用的是Spring5 , 毫無疑問 Spring4 和 Spring 5 肯定有 類的全路徑一樣的類吧,如果使用雙親委派 ,父加載器加載誰?

      部署在同一個web容器中相同的類庫相同的版本可以共享, 比如jdk的核心jar包,否則,如果服務器有n個應用程序,那么要有n份相同的類庫加載進虛擬機。

      web容器 自己依賴的類庫 (tomcat lib目錄下),不能與應用程序的類庫混淆。基于安全考慮,應該讓容器的類庫和程序的類庫隔離開來。

      web容器要支持jsp的修改, jsp 文件最終也是要編譯成class文件才能在虛擬機中運行, web容器需要支持 jsp 修改后不用重啟 ,就是熱加載的功能。

      結合上面的4個問題,我們看下雙親委派能不能支持?

      第一個問題,如果使用默認的類加載器機制,肯定是無法加載兩個相同類庫的不同版本的,如果使用雙親委派,讓父加載器去加載 ,不管你是什么版本的,只要你的全限定類名一樣,那肯定只有一份,APP 隔離 無法滿足

      第二個問題,默認的類加載器是能夠實現的,很好理解嘛, 就是雙親委派的功能,保證唯一性。

      第三個問題和第一個問題一樣。

      第四個問題, 要怎么實現jsp文件的熱加載呢? jsp 文件其實也就是class文件,那么如果修改了,但類名還是一樣,類加載器會直接取方法區中已經存在的,修改后的jsp是不會重新加載的。那么怎么辦呢?可以直接卸載掉這jsp文件的類加載器 .當一個jsp文件修改了,就直接卸載這個jsp類加載器。重新創建類加載器,重新加載jsp文件。 源碼詳見: org.apache.jasper.servlet.JasperLoader

      Tomcat - 都說Tomcat違背了雙親委派機制,到底對不對?

      Tomcat違反了雙親委派機制?

      也不盡然,核心的Java的加載還是遵從雙親委派 。

      Tomcat中 各個web應用自己的類加載器(WebAppClassLoader)會優先加載,打破了雙親委派機制。加載不到時再交給commonClassLoader走雙親委托 .

      原因有二

      為了避免類沖突,每個 webapp 項目中各自使用的類庫要有隔離機制

      不同 webapp 項目支持共享某些類庫

      Tomcat加載機制小結

      當tomcat啟動時,會創建幾種類加載器:

      Bootstrap 引導類加載器 : 加載JVM啟動所需的類,以及標準擴展類(位于jre/lib/ext下)

      System 系統類加載器 : 加載tomcat啟動的類,比如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下

      4. webapp 應用類加載器: 每個應用在部署后,都會創建一個唯一的類加載器。該類加載器會加載位于 WEB-INF/lib下的jar文件中的class 和 WEB-INF/classes下的class文件。

      Common 通用類加載器:加載tomcat使用以及應用通用的一些類,位于CATALINA_HOME/lib下,比如servlet-api.jar

      總之 當應用需要到某個類時,則會按照下面的順序進行類加載:

      1 使用bootstrap引導類加載器加載 (JVM 的東西 )

      2 使用system系統類加載器加載 (tomcat的啟動類Bootstrap包)

      3 使用WebAppClassLoader 加載 WEB-INF/classes (應用自定義的class)

      4 使用WebAppClassLoader 加載在WEB-INF/lib (應用的依賴包)

      5 使用common類加載器在CATALINA_HOME/lib中加載 (tomcat的依賴包,公共的,被各個應用共享的)

      Tomcat 熱加載JasperLoader

      原理:后臺啟動線程監聽jsp文件變化,如果變化了找到該jsp對應的servlet類的加載器引用(gcroot),重新生成新的JasperLoader加載器賦值給引用,然后加載新的jsp對應的servlet類,之前的那個加載器因為沒有gcroot引用了,下一次gc的時候會被銷毀。

      常見錯誤

      NoClassDefFoundError

      NoClassDefFoundError : 由于JVM或者類加載器實例嘗試加載類型的定義,但是該定義卻沒有找到,影響了執行路徑。

      換句話說,在編譯時這個類是能夠被找到的,但是在執行時卻沒有找到。

      NoSuchMethodError

      NoSuchMethodError代表這個類型確實存在,但是一個不正確的版本被加載了。 檢查該類中是否真的有對應的方法

      ClassCastException

      ClassCastException,在一個類加載器的情況下,一般出現這種錯誤都會是在轉型操作時,比如:A a = (A) method();,很容易判斷出來method()方法返回的類型不是類型A,但是在 JavaEE 多個類加載器的環境下可能會出現一些不好去定位的情況。

      Tomcat 容器

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:prometheus以監控Pod TCP連接數為例刪除一個或多個metrics指標
      下一篇:Excel2016表格怎么制作車輛行駛記錄表?
      相關文章
      国产亚洲人成网站在线观看不卡| 亚洲成a人片在线播放| 亚洲人成在线播放网站| 亚洲人成无码www久久久| 亚洲国产精品嫩草影院久久| 亚洲AV无码AV男人的天堂不卡| 国产成人亚洲合集青青草原精品 | 亚洲精品美女在线观看| 久久亚洲日韩精品一区二区三区| 亚洲VA中文字幕无码一二三区| 精品国产综合成人亚洲区| 欧洲亚洲国产清在高| 亚洲精品无码久久千人斩| 久久被窝电影亚洲爽爽爽| 亚洲精品白浆高清久久久久久| 亚洲va无码专区国产乱码| 亚洲成a人片在线观看无码| 亚洲成AV人片在线观看WWW| 久久久无码精品亚洲日韩蜜桃| 久久精品亚洲综合| 久久精品国产亚洲AV电影| 亚洲精品不卡视频| 国产成人精品日本亚洲网址| 日本亚洲色大成网站www久久| 亚洲欧洲免费无码| 国产成人亚洲精品无码AV大片| 亚洲国产精品成人| 亚洲色自偷自拍另类小说| 亚洲阿v天堂在线| 亚洲精彩视频在线观看| 亚洲中文久久精品无码1| 亚洲欧洲免费无码| 国产亚洲精品第一综合| 国产成人精品久久亚洲高清不卡 | 亚洲精品少妇30p| 97久久精品亚洲中文字幕无码| 亚洲国产成人久久| 亚洲乱码av中文一区二区| 亚洲Av无码乱码在线观看性色| 久久亚洲国产精品五月天婷| 亚洲精品成人片在线播放|