电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

一篇文章講透Tomcat的類加載機(jī)制

瀏覽:128日期:2023-03-19 16:51:41
目錄
  • - 前言 -
  • - JVM 類加載器 -
    • 1、JVM類加載器
    • 2、類加載器的源碼
  • - Tomcat 的類加載機(jī)制 -
    • 1、加載機(jī)制的特點(diǎn)
    • 2、Tomcat 的類加載方案
    • 3、分析應(yīng)用類加載器的加載過(guò)程
  • 總結(jié)

    - 前言 -

    你了解 Apache Tomcat 的類加載機(jī)制嗎?本文將從底層原理切入,徹底揭秘 Tomcat 類加載所涉及的源碼、機(jī)制和方案,助你深入掌握 Tomcat 類加載核心!

    - JVM 類加載器 -

    1、JVM類加載器

    說(shuō)起 Tomcat 類加載器,就不得不先簡(jiǎn)單說(shuō)一下 JVM 類加載器,如下圖所示:

    • 啟動(dòng)類加載器:Bootstrap ClassLoader,用于加載JVM提供的基礎(chǔ)運(yùn)行類,即位于%JAVA_HOME%/jre/lib目錄下的核 心類庫(kù);
    • 擴(kuò)展類加載器:Extension ClassLoader, Java提供的一個(gè)標(biāo)準(zhǔn)的擴(kuò)展機(jī)制用于加載除核心類庫(kù)外的Jar包,即只要復(fù)制 到指定的擴(kuò)展目錄(可以多個(gè))下的Jar, JVM會(huì)自動(dòng)加載(不需要通過(guò)-classpath指定)。默認(rèn)的擴(kuò)展目錄是%JAVA_HOME%加e/lib/ext。典型的應(yīng)用場(chǎng)景就是,Java使用該類加載 器加載JVM默認(rèn)提供的但是不屬于核心類庫(kù)的Jar。不推薦將應(yīng)用程序依賴的 類庫(kù)放置到擴(kuò)展目錄下,因?yàn)樵撃夸浵碌念悗?kù)對(duì)所有基于該JVM運(yùn)行的應(yīng)用程序可見(jiàn);
    • 應(yīng)用程序類加載器:Application ClassLoader ,用于加載環(huán)境變量CLASSPATH (不推薦使用)指定目錄下的或者-classpath運(yùn)行 參數(shù)指定的Jar包。System類加載器通常用于加載應(yīng)用程序Jar包及其啟動(dòng)入口類(Tomcat 的Bootstrap類即由System類加載器加載)。

    這些類加載器的工作原理是一樣的,區(qū)別是它們的加載路徑不同,也就是說(shuō) findClass 這個(gè)方法查找的路徑不同。

    雙親委托機(jī)制是為了保證一個(gè) Java 類在 JVM 中是唯一的,假如你不小心寫(xiě)了一個(gè)與 JRE 核心類同名的類,比如 Object 類,雙親委托機(jī)制能保證加載的是 JRE 里的那個(gè) Object 類,而不是你寫(xiě)的 Object 類。

    這是因?yàn)?AppClassLoader 在加載你的 Object 類時(shí),會(huì)委托給 ExtClassLoader 去加載,而 ExtClassLoader 又會(huì)委托給 BootstrapClassLoader,BootstrapClassLoader 發(fā)現(xiàn)自己已經(jīng)加載過(guò)了 Object 類,會(huì)直接返回,不會(huì)去加載你寫(xiě)的 Object 類。

    這里請(qǐng)注意,類加載器的父子關(guān)系不是通過(guò)繼承來(lái)實(shí)現(xiàn)的,比如 AppClassLoader 并不是 ExtClassLoader 的子類,而是說(shuō) AppClassLoader 的 parent 成員變量指向 ExtClassLoader 對(duì)象。同樣的道理,如果你要自定義類加載器,不去繼承 AppClassLoader,而是繼承 ClassLoader 抽象類,再重寫(xiě) findClass 和 loadClass 方法即可,Tomcat 就是通過(guò)自定義類加載器來(lái)實(shí)現(xiàn)自己的類加載邏輯。不知道你發(fā)現(xiàn)沒(méi)有,如果你要打破雙親委托機(jī)制,就需要重寫(xiě) loadClass 方法,因?yàn)?loadClass 的默認(rèn)實(shí)現(xiàn)就是雙親委托機(jī)制。

    2、類加載器的源碼

    public abstract class ClassLoader {  //  每個(gè)類加載器都有一個(gè)父加載器  private final ClassLoader parent;  public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);    }     protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException    {    // First, check if the class has already been loaded    Class<?> c = findLoadedClass(name);   // 如果沒(méi)有加載過(guò)    if (c == null) {if (parent != null) {  //  先委托給父加載器去加載,注意這是個(gè)遞歸調(diào)用 c = parent.loadClass(name, false);} else { // 如果父加載器為空,查找 Bootstrap 加載器是不是加載過(guò)了   c = findBootstrapClassOrNull(name);}          // 如果父加載器沒(méi)加載成功,調(diào)用自己的 findClass 去加載if (c == null) {    c = findClass(name);}    }     return c;}    }    //ClassLoader 中findClass方式需要被子類覆蓋,下面這段代碼就是對(duì)應(yīng)代碼      protected Class<?> findClass(String name){       //1. 根據(jù)傳入的類名 name,到在特定目錄下去尋找類文件,把.class 文件讀入內(nèi)存  ...       //2. 調(diào)用 defineClass 將字節(jié)數(shù)組轉(zhuǎn)成 Class 對(duì)象       return defineClass(buf, off, len);    }      // 將字節(jié)碼數(shù)組解析成一個(gè) Class 對(duì)象,用 native 方法實(shí)現(xiàn)    protected final Class<?> defineClass(byte[] b, int off, int len){        }    }

    我們自定義類加載器就需要重寫(xiě)ClassLoader的loadClass方法。

    - Tomcat 的類加載機(jī)制 -

    1、加載機(jī)制的特點(diǎn)

    隔離性:Web應(yīng)用類庫(kù)相互隔離,避免依賴庫(kù)或者應(yīng)用包相互影響。設(shè)想一下,如果我們 有兩個(gè)Web應(yīng)用,一個(gè)釆用了Spring 2.5, 一個(gè)采用了Spring 4.0,而應(yīng)用服務(wù)器使用一個(gè) 類加載器加載,那么Web應(yīng)用將會(huì)由于Jar包覆蓋而導(dǎo)致無(wú)法啟動(dòng)成功;

    靈活性:既然Web應(yīng)用之間的類加載器相互獨(dú)立,那么我們就能只針對(duì)一個(gè)Web應(yīng)用進(jìn)行 重新部署,此時(shí)該Web應(yīng)用的類加載器將會(huì)重新創(chuàng)建,而且不會(huì)影響其他Web應(yīng)用。如果 釆用一個(gè)類加載器,顯然無(wú)法實(shí)現(xiàn),因?yàn)橹挥幸粋€(gè)類加載器的時(shí)候,類之間的依賴是雜 亂無(wú)章的,無(wú)法完整地移除某個(gè)Web應(yīng)用的類;

    性能:由于每個(gè)Web應(yīng)用都有一個(gè)類加載器,因此Web應(yīng)用在加載類時(shí),不會(huì)搜索其他 Web應(yīng)用包含的Jar包,性能自然高于應(yīng)用服務(wù)器只有一個(gè)類加載器的情況。

    2、Tomcat 的類加載方案

    • 引導(dǎo)類加載器 和 擴(kuò)展類加載器 的作⽤不變;
    • 系統(tǒng)類加載器正常情況下加載的是 CLASSPATH 下的類,但是 Tomcat 的啟動(dòng)腳本并未使⽤該變量,⽽是加載tomcat啟動(dòng)的類,⽐如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下;
    • Common 通⽤類加載器加載Tomcat使⽤以及應(yīng)⽤通⽤的⼀些類,位于CATALINA_HOME/lib下,⽐如servlet-api.jar;
    • Catalina ClassLoader ⽤于加載服務(wù)器內(nèi)部可⻅類,這些類應(yīng)⽤程序不能訪問(wèn);
    • SharedClassLoader ⽤于加載應(yīng)⽤程序共享類,這些類服務(wù)器不會(huì)依賴;
    • WebappClassLoader,每個(gè)應(yīng)⽤程序都會(huì)有⼀個(gè)獨(dú)⼀⽆⼆的Webapp ClassLoader,他⽤來(lái)加載本應(yīng)⽤程序 /WEB-INF/classes 和 /WEB-INF/lib 下的類。

    tomcat 8.5 默認(rèn)改變了嚴(yán)格的雙親委派機(jī)制:

    • 從緩存中加載;
    • 如果緩存中沒(méi)有,會(huì)先調(diào)用ExtClassLoader進(jìn)行加載, 擴(kuò)展類加載器是遵循雙親委派的,他會(huì)調(diào)用bootstrap,查看對(duì)應(yīng)的lib有沒(méi)有,然后回退給ExtClassLoader對(duì)擴(kuò)展包下的數(shù)據(jù)進(jìn)行加載;
    • 如果未加載到,則從 /WEB-INF/classes加載;
    • 如果未加載到,則從 /WEB-INF/lib/*.jar 加載如果未加載到,WebAppclassLoader 會(huì)委派給SharedClassLoader,SharedClassLoad會(huì)委派給CommonClassLoader.....,依次委派給BootstrapClassLoader, 然后BootstrapClassLoader 在自己目錄中查找對(duì)應(yīng)的類如果有則進(jìn)行加載,如果沒(méi)有他會(huì)委派給下一級(jí)ExtClassLoader,ExtClassLoader再查找自己目錄下的類,如果有則加載如果沒(méi)有則委派給下一級(jí)……遵循雙親委派原則。

    3、分析應(yīng)用類加載器的加載過(guò)程

    應(yīng)用類加載器為WebappClassLoader ,他的loadClass在他的父類WebappClassLoaderBase中。

      public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {    if (log.isDebugEnabled())log.debug("loadClass(" + name + ", " + resolve + ")");    Class<?> clazz = null;    // Log access to stopped class loader    checkStateForClassLoading(name);        //從當(dāng)前ClassLoader的本地緩存中加載類,如果找到則返回    clazz = findLoadedClass0(name);    if (clazz != null) {if (log.isDebugEnabled())    log.debug("  Returning class from cache");if (resolve)    resolveClass(clazz);return clazz;    }    // 本地緩存沒(méi)有的情況下,調(diào)用ClassLoader的findLoadedClass方法查看jvm是否已經(jīng)加載過(guò)此類,如果已經(jīng)加載則直接返回。    clazz = findLoadedClass(name);    if (clazz != null) {if (log.isDebugEnabled())    log.debug("  Returning class from cache");if (resolve)    resolveClass(clazz);return clazz;    }    String resourceName = binaryNameToPath(name, false);    //此時(shí)的javaseClassLoader是擴(kuò)展類加載器  是把擴(kuò)展類加載器賦值給了javaseClassLoader    ClassLoader javaseLoader = getJavaseClassLoader();    boolean tryLoadingFromJavaseLoader;    try {      .....    //如果可以用getResource得到    //如果能用擴(kuò)展類加載器的getResource得到就證明可以被擴(kuò)展類加載器加載到接下來(lái)安排擴(kuò)展類加載器加載    if (tryLoadingFromJavaseLoader) {try {    //使用擴(kuò)展類加載器進(jìn)行加載    clazz = javaseLoader.loadClass(name);    if (clazz != null) {if (resolve)    resolveClass(clazz);return clazz;    }} catch (ClassNotFoundException e) {    // Ignore}    }    // (0.5) Permission to access this class when using a SecurityManager    if (securityManager != null) {int i = name.lastIndexOf(".");if (i >= 0) {    try {securityManager.checkPackageAccess(name.substring(0,i));    } catch (SecurityException se) {String error = "Security Violation, attempt to use " +    "Restricted Class: " + name;log.info(error, se);throw new ClassNotFoundException(error, se);    }}    }    boolean delegateLoad = delegate || filter(name, true);    // (1) Delegate to our parent if requested    //如果是true就是用父類加載器進(jìn)行加載    if (delegateLoad) {if (log.isDebugEnabled())    log.debug("  Delegating to parent classloader1 " + parent);try {    clazz = Class.forName(name, false, parent);    if (clazz != null) {if (log.isDebugEnabled())    log.debug("  Loading class from parent");if (resolve)    resolveClass(clazz);return clazz;    }} catch (ClassNotFoundException e) {    // Ignore}    }    // (2) Search local repositories    if (log.isDebugEnabled())log.debug("  Searching local repositories");    try {// 本地進(jìn)行加載clazz = findClass(name);if (clazz != null) {    if (log.isDebugEnabled())log.debug("  Loading class from local repository");    if (resolve)resolveClass(clazz);    return clazz;}    } catch (ClassNotFoundException e) {// Ignore    }    // (3) Delegate to parent unconditionally    //到這里還是沒(méi)有加載上再次嘗試使用父類加載器進(jìn)行加載    if (!delegateLoad) {    if (log.isDebugEnabled())    log.debug("  Delegating to parent classloader at end: " + parent);try {    clazz = Class.forName(name, false, parent);    if (clazz != null) {if (log.isDebugEnabled())    log.debug("  Loading class from parent");if (resolve)    resolveClass(clazz);return clazz;    }} catch (ClassNotFoundException e) {    // Ignore}    }}throw new ClassNotFoundException(name);    }

    注:在37行英文注釋中標(biāo)注獲取的是系統(tǒng)類加載器,但我們debug的時(shí)候會(huì)發(fā)現(xiàn)他是擴(kuò)展類加載器,實(shí)際中我們可以推斷出他應(yīng)該是擴(kuò)展類加載器,因?yàn)槿绻覀兗虞d的類在擴(kuò)展類加載器路徑下已經(jīng)存在的話,那我們直接調(diào)用系統(tǒng)類加載器是就是錯(cuò)誤的了,下圖為debug后獲取的類加載器的驗(yàn)證。

    總結(jié)

    tomcat打破了雙親委派的原則,實(shí)際是在應(yīng)用類加載器中打破了雙親委派,其他類加載器還是遵循雙親委派的。

    到此這篇關(guān)于Tomcat類加載機(jī)制的文章就介紹到這了,更多相關(guān)Tomcat類加載機(jī)制內(nèi)容請(qǐng)搜索以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持!

    標(biāo)簽: Tomcat
    主站蜘蛛池模板: 东风体检车厂家_公共卫生体检车_医院体检车_移动体检车-锦沅科贸 | 绿萝净除甲醛|深圳除甲醛公司|测甲醛怎么收费|培训机构|电影院|办公室|车内|室内除甲醛案例|原理|方法|价格立马咨询 | LED灯杆屏_LED广告机_户外LED广告机_智慧灯杆_智慧路灯-太龙智显科技(深圳)有限公司 | ICP备案查询_APP备案查询_小程序备案查询 - 备案巴巴 | 西安耀程造价培训机构_工程预算实训_广联达实作实操培训 | 北京印刷厂_北京印刷_北京印刷公司_北京印刷厂家_北京东爵盛世印刷有限公司 | 淘剧影院_海量最新电视剧,免费高清电影随心观看 | 万濠影像仪(万濠投影仪)百科-苏州林泽仪器 | 鲁尔圆锥接头多功能测试仪-留置针测试仪-上海威夏环保科技有限公司 | 披萨石_披萨盘_电器家电隔热绵加工定制_佛山市南海区西樵南方综合保温材料厂 | 生物除臭剂-除味剂-植物-污水除臭剂厂家-携葵环保有限公司 | 不锈钢搅拌罐_高速搅拌罐厂家-无锡市凡格德化工装备科技有限公司 | 哈尔滨京科脑康神经内科医院-哈尔滨治疗头痛医院-哈尔滨治疗癫痫康复医院 | 组织研磨机-高通量组织研磨仪-实验室多样品组织研磨机-东方天净 传递窗_超净|洁净工作台_高效过滤器-传递窗厂家广州梓净公司 | 智能垃圾箱|垃圾房|垃圾分类亭|垃圾分类箱专业生产厂家定做-宿迁市传宇环保设备有限公司 | 水性绝缘漆_凡立水_绝缘漆树脂_环保绝缘漆-深圳维特利环保材料有限公司 | 密集架|电动密集架|移动密集架|黑龙江档案密集架-大量现货厂家销售 | 优宝-汽车润滑脂-轴承润滑脂-高温齿轮润滑油脂厂家 | 尚为传动-专业高精密蜗轮蜗杆,双导程蜗轮蜗杆,蜗轮蜗杆减速机,蜗杆减速机生产厂家 | 陶氏道康宁消泡剂_瓦克消泡剂_蓝星_海明斯德谦_广百进口消泡剂 | 基本型顶空进样器-全自动热脱附解吸仪价格-AutoHS全模式-成都科林分析技术有限公司 | 提升海外网站流量,增加国外网站访客UV,定制海外IP-访客王 | 400电话_400电话申请_888元包年_400电话办理服务中心_400VIP网 | 集装箱标准养护室-集装箱移动式养护室-广州璟业试验仪器有限公司 | 工业胀紧套_万向节联轴器_链条-规格齐全-型号选购-非标订做-厂家批发价格-上海乙谛精密机械有限公司 | 专业甜品培训学校_广东糖水培训_奶茶培训_特色小吃培训_广州烘趣甜品培训机构 | 大连海岛旅游网>>大连旅游,大连海岛游,旅游景点攻略,海岛旅游官网 | 质检报告_CE认证_FCC认证_SRRC认证_PSE认证_第三方检测机构-深圳市环测威检测技术有限公司 | 机器视觉检测系统-视觉检测系统-机器视觉系统-ccd检测系统-视觉控制器-视控一体机 -海克易邦 | 直流电能表-充电桩电能表-导轨式电能表-智能电能表-浙江科为电气有限公司 | 三板富 | 专注于新三板的第一垂直服务平台 | 拖鞋定制厂家-品牌拖鞋代加工厂-振扬实业中国高端拖鞋大型制造商 | 制氮设备-变压吸附制氮设备-制氧设备-杭州聚贤气体设备制造有限公司 | 皮带机_移动皮带机_大倾角皮带机_皮带机厂家 - 新乡市国盛机械设备有限公司 | 电磁辐射仪-电磁辐射检测仪-pm2.5检测仪-多功能射线检测仪-上海何亦仪器仪表有限公司 | 户外-组合-幼儿园-不锈钢-儿童-滑滑梯-床-玩具-淘气堡-厂家-价格 | 博医通医疗器械互联网供应链服务平台_博医通 | 定制奶茶纸杯_定制豆浆杯_广东纸杯厂_[绿保佳]一家专业生产纸杯碗的厂家 | 油液红外光谱仪-油液监测系统-燃油嗅探仪-上海冉超光电科技有限公司 | 济南网站策划设计_自适应网站制作_H5企业网站搭建_济南外贸网站制作公司_锐尚 | EDLC超级法拉电容器_LIC锂离子超级电容_超级电容模组_软包单体电容电池_轴向薄膜电力电容器_深圳佳名兴电容有限公司_JMX专注中高端品牌电容生产厂家 |