成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

"深入探索:Tomcat 類加載機制揭秘"

開發 前端
Java 虛擬機將描述類的字節碼數據從 Class 文件加載至內存,并對其進行嚴格的校驗、轉換解析和初始化,最終生成可供虛擬機直接執行的 Java 類型。這一過程便是虛擬機的類加載機制。

前言

在探究 Tomcat 類加載機制之前,讓我們重溫一下 Java 默認的類加載器,加深對其的理解。如同作者在《深入理解 Java 虛擬機》第二版中所言,類加載機制對于理解 Java 運行時環境至關重要。

什么是類加載機制

Java 虛擬機將描述類的字節碼數據從 Class 文件加載至內存,并對其進行嚴格的校驗、轉換解析和初始化,最終生成可供虛擬機直接執行的 Java 類型。這一過程便是虛擬機的類加載機制。

虛擬機設計者將類加載階段中“根據全限定名獲取描述類信息的二進制字節流”這一關鍵步驟委托給了外部實現,賦予應用程序自行決定如何獲取所需類的權利。負責執行這一任務的代碼模塊被稱為“類加載器”。

類與類加載器的關系

類加載器雖然只負責加載類,但其影響卻遠超類加載階段本身。對于任何一個類,它與加載它的類加載器共同決定了該類在 Java 虛擬機中的唯一性,就好比每個類加載器都擁有一個獨立的“類倉庫”,每個倉庫中的類都是獨一無二的。因此,判斷兩個類是否相同,只有在它們由同一個類加載器加載的前提下才有意義。即使兩個類來自同一個 Class 文件,被同一個虛擬機加載,只要加載它們的類加載器不同,它們也必然被視為不同的類。

什么是雙親委任模型

  1. 從 Java 虛擬機的視角來看,類加載器僅存在兩種類型:一是啟動類加載器(Bootstrap ClassLoader),它由 C++語言實現(僅限于 HotSpot 虛擬機),是虛擬機自身的一部分;二是所有其他類加載器,它們均由 Java 語言實現,獨立于虛擬機外部,并且都繼承自抽象類 java.lang.ClassLoader。
  2. 從 Java 開發者的角度,類加載器可以更細致地劃分,大部分 Java 程序員會接觸到以下三種系統提供的類加載器:

啟動類加載器(Bootstrap ClassLoader):它負責加載位于 JAVA_HOME/lib 目錄下的,或者被-Xbootclasspath 參數指定的路徑中的,并且被虛擬機識別的類庫(僅根據文件名識別,例如 rt.jar,其他名字的類庫即使放在 lib 目錄下也不會被重載)。

擴展類加載器(Extension ClassLoader):由 sun.misc.Launcher$ExtClassLoader 實現,它負責加載位于 JAVA_HOME/lib/ext 目錄下的,或由 java.ext.dirs 系統變量指定的路徑中的所有類庫。開發者可以直接使用擴展類加載器。

應用程序類加載器(Application ClassLoader):由 sun.misc.Launcher$AppClassLoader 實現,由于它是 ClassLoader 中的 getSystemClassLoader 方法的返回值,因此也被稱為系統類加載器。它負責加載用戶類路徑(ClassPath)上所指定的類庫。開發者可以直接使用這個類加載器,如果應用程序沒有自定義類加載器,它通常是程序中的默認類加載器。


這些類加載器之間的關系一般如下圖所示:

圖片圖片

圖中各個類加載器之間的關系被稱為類加載器的雙親委派模型(Parents Delegation Mode)。雙親委派模型規定,除了頂層的啟動類加載器之外,其他所有類加載器都應該由其父類加載器加載。這里類加載器之間的父子關系通常不通過繼承實現,而是使用組合關系來復用父加載器的代碼。

類加載器的雙親委派模型在 JDK 1.2 時期被引入,并被廣泛應用于之后的 Java 程序中,但它并非強制性約束模型,而是 Java 設計者推薦給開發者的一種類加載器實現方式。

雙親委派模型的工作流程如下:當一個類加載器收到類加載請求時,它不會立即嘗試加載該類,而是將請求委托給父類加載器處理。每一層級類加載器都遵循這一原則,最終請求將傳遞到頂層的啟動類加載器。只有當父加載器反饋無法完成請求(在其搜索范圍內沒有找到所需的類)時,子加載器才會嘗試自己加載。

為什么要使用雙親委派模型

如果沒有使用雙親委派模型,而是由各個類加載器自行加載類,那么如果用戶編寫了一個名為java.lang.Object的類并將其放置在程序的 ClassPath 中,系統中就會出現多個不同的 Object 類。Java 類型體系中最基礎的行為將無法保證,應用程序也將變得混亂不堪。

雙親委任模型時如何實現的

非常簡單,雙親委派模型的核心邏輯體現在 java.lang.ClassLoader 中的 loadClass 方法中。

圖片圖片

首先判斷若類尚未加載,則委派父加載器嘗試加載。父加載器為空時,則默認委托啟動類加載器。若父加載器加載失敗,則拋出 ClassNotFoundException 異常,隨后調用自定義 findClass 方法進行加載。

如何破壞雙親委任模型

雙親委派模型并非強制性約束,而是 Java 設計者推薦的類加載器實現方式。雖然大部分類加載器都遵循這一模型,但也有例外。迄今為止,雙親委派模型曾三次被“打破”。

第一次發生在雙親委派模型出現之前,即 JDK 1.2 發布之前。

第二次則是模型本身的缺陷所致。雙親委派模型有效地解決了基礎類的統一加載問題(越基礎的類由越上層的加載器加載),然而,并非所有基礎類都只被用戶代碼調用。如果基礎類需要調用用戶代碼,就會出現問題。

這并非不可能。JNDI 服務就是一個典型例子。作為 Java 的標準服務,JNDI 的代碼由啟動類加載器加載(在 JDK 1.3 時就已包含在 rt.jar 中),但它需要調用獨立廠商實現并部署在應用程序 ClassPath 下的 JNDI 接口提供者(SPI,Service Provider Interface)的代碼。然而,啟動類加載器無法“識別”這些代碼,因為它們并不在 rt.jar 中。為了解決這個問題,啟動類加載器需要加載這些代碼。

為了解決這個問題,Java 設計團隊引入了一個名為線程上下文類加載器(Thread Context ClassLoader)的設計。這個類加載器可以通過 java.lang.Thread 類的 setContextClassLoader 方法進行設置。如果在創建線程時尚未設置,它會從父線程中繼承一個;如果在應用程序的全局范圍內都沒有設置,那么這個類加載器默認就是應用程序類加載器。

有了線程上下文加載器,JNDI 服務便可以使用它來加載所需的 SPI 代碼。這相當于父類加載器請求子類加載器完成類加載,打破了雙親委派模型的層次結構,逆向使用類加載器,實際上已經違背了模型的一般性原則。但這是無奈之舉,Java 中所有涉及 SPI 加載的動作基本上都采用這種方式,例如 JNDI、JDBC、JCE、JAXB、JBI 等。

第三次破壞則是為了實現熱插拔、熱部署、模塊化。這意味著添加或刪除功能無需重啟,只需將模塊連同其類加載器一起替換,即可實現代碼熱替換。

Tomcat 的類加載器是怎么設計的

首先,我們來思考個問題:

Tomcat 如果使用默認的類加載機制行不行?

細細想一下,Tomcat 作為一款 Web 容器,其存在的意義何在?到底是為了解決怎樣的問題?

  1. Web 容器或需承載多個應用程序,而不同應用可能依賴于同一第三方類庫的不同版本。為確保應用間相互隔離,每個應用程序的類庫應保持獨立,避免彼此干擾。
  2. 同一 Web 容器中的相同類庫版本可共享,以避免資源浪費。若每個應用程序都獨立加載相同類庫,則當服務器承載十個應用程序時,將會加載十份相同的類庫,這無疑是極不合理的。
  3. Web 容器自身亦有其依賴的類庫,不可與應用程序的類庫混淆。出于安全考慮,容器的類庫與應用程序的類庫應嚴格隔離,互不干擾。
  4. Web 容器需具備對 JSP 文件修改的支持。眾所周知,JSP 文件最終需編譯成 Class 文件才能在虛擬機中運行。然而,程序運行后修改 JSP 文件已成常態,否則容器便無實際意義。因此,Web 容器應支持 JSP 修改后無需重啟服務器,以提高開發效率。

再回頭看問題,Tomcat 如果使用默認的類加載機制行不行?

答案是不行的。為什么?

首先,默認的類加載器機制無法加載相同類庫的不同版本。其機制只關注全限定類名,而不會區分版本。因此,第一個和第三個問題無法通過默認機制解決。

其次,默認類加載器的職責正是確保類庫的唯一性,這與第二個問題并不沖突。

至于第四個問題,熱修改 JSP 文件面臨挑戰。JSP 文件最終編譯成 Class 文件,修改后的 JSP 文件仍擁有相同的類名,導致類加載器直接從方法區中獲取已存在的 Class 文件,無法加載修改后的內容。

為了解決這個問題,可以為每個 JSP 文件創建唯一的類加載器。當 JSP 文件修改后,直接卸載該類加載器,并重新創建類加載器,從而重新加載修改后的 JSP 文件。

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

首先看下 Tomcat 的設計圖:

圖片圖片

觀察這張圖,我們看到了多個類加載器,其中除了 JDK 自帶的類加載器之外,我們尤其關注 Tomcat 自身持有的類加載器。細細觀察,我們會發現 Catalina 類加載器和 Shared 類加載器并非父子關系,而是兄弟關系。這種設計背后的緣由,需要我們分析每個類加載器的用途才能明了。

從圖中我們能了解到 Tomcat 類加載器體系結構的設計精妙,每個類加載器各司其職,確保了系統的穩定性和安全性。

  • Common 類加載器 負責加載 Tomcat 和 Web 應用共同復用的類,例如日志框架、通用工具庫等。
  • Catalina 類加載器 專注于加載 Tomcat 自身的類,這些類在 Web 應用中不可見,確保了 Tomcat 核心功能的獨立性。
  • Shared 類加載器 負責加載所有 Web 應用共同復用的類,例如數據庫連接池、緩存框架等,這些類在 Tomcat 中不可見,避免了應用之間的沖突。
  • WebApp 類加載器 為每個 Web 應用單獨創建,負責加載該應用的類,這些類在 Tomcat 和其他應用中不可見,確保了應用之間的隔離。
  • Jsp 類加載器 為每個 JSP 頁面創建唯一的類加載器,方便實現 JSP 頁面的熱插拔,提高開發效率。

至此,我們對 Tomcat 類加載器體系有了初步了解,接下來將深入探討其源碼實現。由于篇幅所限,詳細分析將在下一篇文章中展開。

責任編輯:武曉燕 來源: 碼上遇見你
相關推薦

2021-09-24 08:10:40

Java 語言 Java 基礎

2024-12-02 09:01:23

Java虛擬機內存

2012-01-18 11:24:18

Java

2021-07-05 06:51:43

Java機制類加載器

2023-10-31 16:00:51

類加載機制Java

2024-03-27 10:14:48

2024-09-06 09:37:45

WebApp類加載器Web 應用

2021-01-06 09:01:05

javaclass

2011-02-25 09:23:00

Java類加載器

2024-03-12 07:44:53

JVM雙親委托機制類加載器

2025-07-01 07:41:37

Java類加載器雙親委派

2024-09-09 09:29:05

2017-09-20 08:07:32

java加載機制

2017-03-08 10:30:43

JVMJava加載機制

2021-04-29 11:18:14

JVM加載機制

2023-05-10 11:07:18

2019-12-09 15:08:30

JavaTomcatWeb

2010-08-06 10:15:35

Flex綁定

2010-08-06 09:45:50

Flex事件機制

2020-10-26 11:20:04

jvm類加載Java
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本污视频 | 超碰成人免费观看 | 免费日韩av | 91精品国产91久久综合桃花 | 岛国毛片在线观看 | 国产一区二区精品在线 | 久久亚洲国产精品 | 99精品免费视频 | 颜色网站在线观看 | 四虎网站在线观看 | 免费的色网站 | 国产精品久久久久久亚洲调教 | 久久99精品久久久久久国产越南 | 亚洲日韩中文字幕一区 | 久久精品视频播放 | 国产精品久久久久国产a级 欧美日本韩国一区二区 | 久久久国产一区 | 成人综合一区 | 成人一区二区三区 | 色综合久久天天综合网 | 久久国 | 国产一区二区 | 欧美日韩三区 | 欧美成人猛片aaaaaaa | 日韩免费高清视频 | 国产91丝袜在线18 | 福利视频网站 | 欧美国产激情二区三区 | 91xxx在线观看 | 澳门永久av免费网站 | 国产目拍亚洲精品99久久精品 | 亚洲91 | 先锋资源吧 | 在线色网站 | av在线视 | 精品国产乱码一区二区三区a | 欧美一级在线观看 | 天天弄天天操 | 天天弄| 亚洲人在线播放 | 国产成人精品网站 |