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

您的位置:首頁技術文章
文章詳情頁

Tomcat Catalina為什么不new出來原理解析

瀏覽:220日期:2023-03-19 16:51:53

一、Catalina為什么不new出來?

掌握了Java的類加載器和雙親委派機制,現在我們就可以回答正題上來了,Tomcat的類加載器是怎么設計的?

1.Web容器的特性

Web容器有其自身的特殊性,所以在類加載器這塊是不能完全使用JVM的類加載器的雙親委派機制的。在Web容器中我們應該要滿足如下的特性:

隔離性

部署在同一個Web容器上的兩個Web應用程序所使用的Java類庫可以實現相互隔離。設想一下,兩個Web應用,一個使用了Spring3.0,另一個使用了新的的5.0,應用服務器使用一個類加載器,Web應用將會因為jar包覆蓋而無法啟動。

靈活性:

Web應用之間的類加載器相互獨立,那么就能針對一個Web應用進行重新部署,此時Web應用的類加載器會被重建,而且不會影響其他的Web應用。如果采用一個類加載器,類之間的依賴是雜亂復雜的,無法完全移出某個應用的類。

性能:

性能也是一個比較重要的點。部署在同一個Web容器上的兩個Web應用程序所使用的Java類庫可以互相共享。這個需求也很常見,例如,用戶可能有10個使用Spring框架的應用程序部署在同一臺服務器上,如果把10份Spring分別存放在各個應用程序的隔離目錄中,將會是很大的資源浪費——這主要倒不是浪費磁盤空間的問題,而是指類庫在使用時都要被加載到Web容器的內存,如果類庫不能共享,虛擬機的方法區就會很容易出現過度膨脹的風險。

2.Tomcat類加載器結構

明白了Web容器的類加載器有多個,再來看tomcat的類加載器結構。

首先上張圖,整體看下tomcat的類加載器:

可以看到在原先的java類加載器基礎上,tomcat新增了幾個類加載器,包括3個基礎類加載器和每個Web應用的類加載器,其中3個基礎類加載器可在conf/catalina.properties中配置,具體介紹下:

Common

以應用類加載器為父類,是tomcat頂層的公用類加載器,其路徑由conf/catalina.properties中的common.loader指定,默認指向${catalina.base}/lib下的包。

Catalina

以Common類加載器為父類,是用于加載Tomcat應用服務器的類加載器,其路徑由server.loader指定,默認為空,此時tomcat使用Common類加載器加載應用服務器。

Shared

以Common類加載器為父類,是所有Web應用的父類加載器,其路徑由shared.loader指定,默認為空,此時tomcat使用Common類加載器作為Web應用的父加載器。

Web應用

以Shared類加載器為父類,加載/WEB-INF/classes目錄下的未壓縮的Class和資源文件以及/WEB-INF/lib目錄下的jar包,該類加載器只對當前Web應用可見,對其他Web應用均不可見。

默認情況下,Common、Catalina、Shared類加載器是同一個,但可以配置3個不同的類加載器,使他們各司其職。

首先,Common類加載器復雜加載Tomcat應用服務器內部和Web應用均可見的類,如Servlet規范相關包和一些通用工具包。

其次,Catalina類加載器負責只有Tomcat應用服務器內部可見的類,這些類對Web應用不可見。比如,想實現自己的會話存儲方案,而且該方案依賴了一些第三方包,當然是不希望這些包對Web應用可見,這時可以配置server.load,創建獨立的Catalina類加載器。

再次,Shared類復雜加載Web應用共享類,這些類tomcat服務器不會依賴

3.Tomcat源碼分析

3.1 CatalinClassLoader

首先來看看Tomcat的類加載器的繼承結構

可以看到繼承的結構和我們上面所寫的類加載器的結構不同。

大家需要注意雙親委派機制并不是通過繼承來實現的,而是相互之間組合而形成的。

所以AppClassLoader沒有繼承自 ExtClassLoader,WebappClassLoader也沒有繼承自AppClassLoader。

至于Common ClassLoader ,Shared ClassLoader,Catalina ClassLoader則是在啟動時初始化的三個不同名字的URLClassLoader。

先來看看Bootstrap#init()方法。init方法會調用initClassLoaders,同樣也會將Catalina ClassLoader設置到當前線程設置到當前線程,進入initClassLoaders來看看。

    private void initClassLoaders() {try {    // 創建 commonLoader  catalinaLoader sharedLoader    commonLoader = createClassLoader("common", null);    if (commonLoader == null) {// no config file, default to this loader - we might be in a "single" env.commonLoader = this.getClass().getClassLoader();    }    // 默認情況下 server.loader 和 shared.loader 都為空則會返回 commonLoader 類加載器    catalinaLoader = createClassLoader("server", commonLoader);    sharedLoader = createClassLoader("shared", commonLoader);} catch (Throwable t) {    handleThrowable(t);    log.error("Class loader creation threw exception", t);    System.exit(1);}    }

我們可以看到在initClassLoaders()方法中完成了CommonClassLoader, CatalinaClassLoader,和SharedClassLoader的創建,而且進入到createClassLoader方法中。

可以看到這三個基礎類加載器所加載的資源剛好對應conf/catalina.properties中的common.loader,server.loader,shared.loader

3.2 層次結構

Common/Catalina/Shared ClassLoader的創建好了之后就會維護相互之間的組合關系

其實也就是設置了父加載器

3.3 具體的加載過程

源碼比較長,直接進入到 WebappClassLoaderBase中的 LoadClass方法

@Override    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);    // (0) Check our previously loaded local class cache    // 檢查WebappClassLoader中是否加載過此類    clazz = findLoadedClass0(name);    if (clazz != null) {if (log.isDebugEnabled()) {    log.debug("  Returning class from cache");}if (resolve) {    resolveClass(clazz);}return clazz;    }    // (0.1) Check our previously loaded class cache    // 如果第一步沒有找到,則繼續檢查JVM虛擬機中是否加載過該類    clazz = findLoadedClass(name);    if (clazz != null) {if (log.isDebugEnabled()) {    log.debug("  Returning class from cache");}if (resolve) {    resolveClass(clazz);}return clazz;    }    // (0.2) Try loading the class with the bootstrap class loader, to prevent    //       the webapp from overriding Java SE classes. This implements    //       SRV.10.7.2    // 如果前兩步都沒有找到,則使用系統類加載該類(也就是當前JVM的ClassPath)。    // 為了防止覆蓋基礎類實現,這里會判斷class是不是JVMSE中的基礎類庫中類。    String resourceName = binaryNameToPath(name, false);    ClassLoader javaseLoader = getJavaseClassLoader();    boolean tryLoadingFromJavaseLoader;    try {// Use getResource as it won"t trigger an expensive// ClassNotFoundException if the resource is not available from// the Java SE class loader. However (see// https://bz.apache.org/bugzilla/show_bug.cgi?id=58125 for// details) when running under a security manager in rare cases// this call may trigger a ClassCircularityError.// See https://bz.apache.org/bugzilla/show_bug.cgi?id=61424 for// details of how this may trigger a StackOverflowError// Given these reported errors, catch Throwable to ensure any// other edge cases are also caughtURL url;if (securityManager != null) {    PrivilegedAction<URL> dp = new PrivilegedJavaseGetResource(resourceName);    url = AccessController.doPrivileged(dp);} else {    url = javaseLoader.getResource(resourceName);}tryLoadingFromJavaseLoader = (url != null);    } catch (Throwable t) {// Swallow all exceptions apart from those that must be re-thrownExceptionUtils.handleThrowable(t);// The getResource() trick won"t work for this class. We have to// try loading it directly and accept that we might get a// ClassNotFoundException.tryLoadingFromJavaseLoader = true;    }    if (tryLoadingFromJavaseLoader) {try {    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 = sm.getString("webappClassLoader.restrictedPackage", name);log.info(error, se);throw new ClassNotFoundException(error, se);    }}    }    // 檢查是否 設置了delegate屬性,設置為true,那么就會完全按照JVM的"雙親委托"機制流程加載類。    boolean delegateLoad = delegate || filter(name, true);    // (1) Delegate to our parent if requested    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    // 若是沒有委托,則默認會首次使用WebappClassLoader來加載類。通過自定義findClass定義處理類加載規則。    // findClass()會去Web-INF/classes 目錄下查找類。    if (log.isDebugEnabled()) {log.debug("  Searching local repositories");    }    try {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    // 若是WebappClassLoader在/WEB-INF/classes、/WEB-INF/lib下還是查找不到class,    // 那么無條件強制委托給System、Common類加載器去查找該類。    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);    }

Web應用類加載器默認的加載順序是:

  • (1).先從緩存中加載;
  • (2).如果沒有,則從JVM的Bootstrap類加載器加載;
  • (3).如果沒有,則從當前類加載器加載(按照WEB-INF/classes、WEB-INF/lib的順序);
  • (4).如果沒有,則從父類加載器加載,由于父類加載器采用默認的委派模式,所以加載順序是AppClassLoader、Common、Shared。

tomcat提供了delegate屬性用于控制是否啟用java委派模式,默認false(不啟用),當設置為true時,tomcat將使用java的默認委派模式,這時加載順序如下:

  • (1).先從緩存中加載;
  • (2).如果沒有,則從JVM的Bootstrap類加載器加載;
  • (3).如果沒有,則從父類加載器加載,加載順序是AppClassLoader、Common、Shared。
  • (4).如果沒有,則從當前類加載器加載(按照WEB-INF/classes、WEB-INF/lib的順序)

以上就是Tomcat Catalina為什么不new出來原理解析的詳細內容,更多關于Tomcat Catalina原理的資料請關注其它相關文章!

標簽: Tomcat
主站蜘蛛池模板: 培训无忧网-教育培训咨询招生第三方平台 | 炒货机-炒菜机-炒酱机-炒米机@霍氏机械 | 外贮压-柜式-悬挂式-七氟丙烷-灭火器-灭火系统-药剂-价格-厂家-IG541-混合气体-贮压-非贮压-超细干粉-自动-灭火装置-气体灭火设备-探火管灭火厂家-东莞汇建消防科技有限公司 | 机床主轴维修|刀塔维修|C轴维修-常州翔高精密机械有限公司 | 烟气在线监测系统_烟气在线监测仪_扬尘检测仪_空气质量监测站「山东风途物联网」 | 台湾HIWIN上银直线模组|导轨滑块|TBI滚珠丝杆丝杠-深圳汉工 | 邢台人才网_邢台招聘网_邢台123招聘【智达人才网】 | ORP控制器_ORP电极价格-上优泰百科 | 信阳市建筑勘察设计研究院有限公司 | 依维柯自动挡房车,自行式国产改装房车,小型房车价格,中国十大房车品牌_南京拓锐斯特房车 - 南京拓锐斯特房车 | 臭氧发生器_臭氧消毒机 - 【同林品牌 实力厂家】 | 国产离子色谱仪,红外分光测油仪,自动烟尘烟气测试仪-青岛埃仑通用科技有限公司 | 气动调节阀,电动调节阀,自力式压力调节阀,切断阀「厂家」-浙江利沃夫自控阀门 | 无线遥控更衣吊篮_IC卡更衣吊篮_电动更衣吊篮配件_煤矿更衣吊篮-力得电子 | 示波器高压差分探头-国产电流探头厂家-南京桑润斯电子科技有限公司 | 分子精馏/精馏设备生产厂家-分子蒸馏工艺实验-新诺舜尧(天津)化工设备有限公司 | 课件导航网_ppt课件_课件模板_课件下载_最新课件资源分享发布平台 | 磁力轮,磁力联轴器,磁齿轮,钕铁硼磁铁-北京磁运达厂家 | 中开泵,中开泵厂家,双吸中开泵-山东博二泵业有限公司 | 电子巡更系统-巡检管理系统-智能巡检【金万码】 | 北京网站建设首页,做网站选【优站网】,专注北京网站建设,北京网站推广,天津网站建设,天津网站推广,小程序,手机APP的开发。 | 自动气象站_农业气象站_超声波气象站_防爆气象站-山东万象环境科技有限公司 | 无菌检查集菌仪,微生物限度仪器-苏州长留仪器百科 | 大行程影像测量仪-探针型影像测量仪-增强型影像测量仪|首丰百科 大通天成企业资质代办_承装修试电力设施许可证_增值电信业务经营许可证_无人机运营合格证_广播电视节目制作许可证 | 工程管道/塑料管材/pvc排水管/ppr给水管/pe双壁波纹管等品牌管材批发厂家-河南洁尔康建材 | 储气罐,真空罐,缓冲罐,隔膜气压罐厂家批发价格,空压机储气罐规格型号-上海申容压力容器集团有限公司 | 标策网-专注公司商业知识服务、助力企业发展 | 明渠式紫外线杀菌器-紫外线消毒器厂家-定州市优威环保 | 全自动真空上料机_粉末真空上料机_气动真空上料机-南京奥威环保科技设备有限公司 | 【德信自动化】点胶机_全自动点胶机_自动点胶机厂家_塑料热压机_自动螺丝机-深圳市德信自动化设备有限公司 | 软启动器-上海能曼电气有限公司| 中式装修设计_全屋定制家具_实木仿古门窗花格厂家-喜迎门 | 无纺布包装机|径向缠绕包装机|缠绕膜打包机-上海晏陵智能设备有限公司 | SMN-1/SMN-A ABB抽屉开关柜触头夹紧力检测仪-SMN-B/SMN-C-上海徐吉 | Dataforth隔离信号调理模块-信号放大模块-加速度振动传感器-北京康泰电子有限公司 | 上海平衡机-单面卧式动平衡机-万向节动平衡机-圈带动平衡机厂家-上海申岢动平衡机制造有限公司 | 小型数控车床-数控车床厂家-双头数控车床| 中山市派格家具有限公司【官网】| 冷藏车-东风吸污车-纯电动环卫车-污水净化车-应急特勤保障车-程力专汽厂家-程力专用汽车股份有限公司销售二十一分公司 | 橡胶膜片,夹布膜片,橡胶隔膜密封,泵阀设备密封膜片-衡水汉丰橡塑科技公司网站 | 异噻唑啉酮-均三嗪-三丹油-1227-中北杀菌剂厂家 |