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

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

源碼剖析Tomcat類的加載原理

瀏覽:32日期:2023-09-02 20:30:58
目錄Web應(yīng)用程序類加載器(WebappClassLoader)JSP類加載器(JasperLoader)

眾所周知,Java中默認(rèn)的類加載器是以父子關(guān)系存在的,實(shí)現(xiàn)了雙親委派機(jī)制進(jìn)行類的加載,在前文中,我們提到了,雙親委派機(jī)制的設(shè)計(jì)是為了保證類的唯一性,這意味著在同一個(gè)JVM中是不能加載相同類庫(kù)的不同版本的類。

然而與許多服務(wù)器應(yīng)用程序一樣,Tomcat 允許容器的不同部分以及在容器上運(yùn)行的不同Web應(yīng)用程序可以訪問(wèn)的各種不同版本的類庫(kù),這就要求Tomcat必須打破這種雙親委派機(jī)制,通過(guò)實(shí)現(xiàn)自定義的類加載器(即實(shí)現(xiàn)了java.lang.ClassLoader)進(jìn)行類的加載。下面,就讓我們來(lái)看看Tomcat類加載原理是怎樣的。

Tomcat中有兩個(gè)最重要的類加載器,第一個(gè)便是負(fù)責(zé)Web應(yīng)用程序類加載的WebappClassLoader,另一個(gè)便是JSP Servlet類加載器`JasperLoader。

Web應(yīng)用程序類加載器(WebappClassLoader)

上代碼:

public class WebappClassLoader extends WebappClassLoaderBase { public WebappClassLoader() {super(); } public WebappClassLoader(ClassLoader parent) {super(parent); } ...}

我們來(lái)看看WebappClassLoader繼承的WebappClassLoaderBase中實(shí)現(xiàn)的類加載方法loadClass

public abstract class WebappClassLoaderBase extends URLClassLoaderimplements Lifecycle, InstrumentableClassLoader, WebappProperties, PermissionCheck {//...省略不需要關(guān)注的代碼 protected WebappClassLoaderBase() {super(new URL[0]);// 獲取當(dāng)前WebappClassLoader的父加載器系統(tǒng)類加載器ClassLoader p = getParent();if (p == null) { p = getSystemClassLoader();}this.parent = p;// javaseClassLoader變量經(jīng)過(guò)以下代碼的執(zhí)行,// 得到的是擴(kuò)展類加載器(ExtClassLoader)ClassLoader j = String.class.getClassLoader();if (j == null) { j = getSystemClassLoader(); while (j.getParent() != null) {j = j.getParent(); }}this.javaseClassLoader = j;securityManager = System.getSecurityManager();if (securityManager != null) { refreshPolicy();} } //...省略不需要關(guān)注的代碼 @Override public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) { if (log.isDebugEnabled()) {log.debug('loadClass(' + name + ', ' + resolve + ')'); } Class<?> clazz = null; // Web應(yīng)用程序停止?fàn)顟B(tài)時(shí),不允許加載新的類 checkStateForClassLoading(name); // 如果之前加載過(guò)該類,就可以從Web應(yīng)用程序類加載器本地類緩存中查找,// 如果找到說(shuō)明WebappClassLoader之前已經(jīng)加載過(guò)這個(gè)類 clazz = findLoadedClass0(name); if (clazz != null) {if (log.isDebugEnabled()) { log.debug(' Returning class from cache');}if (resolve) { resolveClass(clazz);}return clazz; } // Web應(yīng)用程序本地類緩存中沒(méi)有,可以從系統(tǒng)類加載器緩存中查找,// 如果找到說(shuō)明AppClassLoader之前已經(jīng)加載過(guò)這個(gè)類 clazz = findLoadedClass(name); if (clazz != null) {if (log.isDebugEnabled()) { log.debug(' Returning class from cache');}if (resolve) { resolveClass(clazz);}return clazz; }// 將類似java.lang.String這樣的類名這樣轉(zhuǎn)換成java/lang/String// 這樣的資源文件名 String resourceName = binaryNameToPath(name, false);// 獲取引導(dǎo)類加載器(BootstrapClassLoader) ClassLoader javaseLoader = getJavaseClassLoader(); boolean tryLoadingFromJavaseLoader; try { // 引導(dǎo)類加載器根據(jù)轉(zhuǎn)換后的類名獲取資源url,如果url不為空,就說(shuō)明找到要加載的類URL 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) {ExceptionUtils.handleThrowable(t);tryLoadingFromJavaseLoader = true; } // 首先,從擴(kuò)展類加載器(ExtClassLoader)加載,防止Java核心API庫(kù)被Web應(yīng)用程序類隨意篡改 if (tryLoadingFromJavaseLoader) {try { clazz = javaseLoader.loadClass(name); if (clazz != null) {if (resolve) { resolveClass(clazz);}return clazz; }} catch (ClassNotFoundException e) { // Ignore} } // 當(dāng)使用安全管理器時(shí),允許訪問(wèn)這個(gè)類 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); }} } /* * 如果Web應(yīng)用程序類加載器配置為,<Loader delegate='true'/> 或者滿足下列條件的類: * 當(dāng)前類屬于以下這些jar包中: * annotations-api.jar — Common Annotations 1.2 類。 * catalina.jar — Tomcat 的 Catalina servlet 容器部分的實(shí)現(xiàn)。 * catalina-ant.jar — 可選。用于使用 Manager Web 應(yīng)用程序的 Tomcat Catalina Ant 任務(wù)。 * catalina-ha.jar — 可選。提供基于 Tribes 構(gòu)建的會(huì)話集群功能的高可用性包。 * catalina-storeconfig.jar — 可選。從當(dāng)前狀態(tài)生成 XML 配置文件。 * catalina-tribes.jar — 可選。高可用性包使用的組通信包。 * ecj-*.jar — 可選。Eclipse JDT Java 編譯器用于將 JSP 編譯為 Servlet。 * el-api.jar — 可選。EL 3.0 API。 * jasper.jar — 可選。Tomcat Jasper JSP 編譯器和運(yùn)行時(shí)。 * jasper-el.jar — 可選。Tomcat EL 實(shí)現(xiàn)。 * jaspic-api.jar — JASPIC 1.1 API。 * jsp-api.jar — 可選。JSP 2.3 API。 * servlet-api.jar — Java Servlet 3.1 API。 * tomcat-api.jar — Tomcat 定義的幾個(gè)接口。 * tomcat-coyote.jar — Tomcat 連接器和實(shí)用程序類。 * tomcat-dbcp.jar — 可選?;?Apache Commons Pool 2 和 Apache Commons DBCP 2 的 * 包重命名副本的數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn)。 * tomcat-i18n-**.jar — 包含其他語(yǔ)言資源包的可選 JAR。由于默認(rèn)包也包含在每個(gè)單獨(dú)的JAR * 中,如果不需要消息國(guó)際化,可以安全地刪除它們。 * tomcat-jdbc.jar — 可選。另一種數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn),稱為 Tomcat JDBC 池。有關(guān)詳細(xì)信息,請(qǐng)參閱 文檔。 * tomcat-jni.jar — 提供與 Tomcat Native 庫(kù)的集成。 * tomcat-util.jar — Apache Tomcat 的各種組件使用的通用類。 * tomcat-util-scan.jar — 提供 Tomcat 使用的類掃描功能。 * tomcat-websocket.jar — 可選。Java WebSocket 1.1 實(shí)現(xiàn) * websocket-api.jar — 可選。Java WebSocket 1.1 API * * 此處的filter方法,實(shí)際上tomcat官方將filter類加載過(guò)濾條件,看作是一種類加載器, *將其取名為CommonClassLoader */ boolean delegateLoad = delegate || filter(name, true); // 如果ExtClassLoader沒(méi)有獲取到,說(shuō)明是非JRE核心類,那么就從系統(tǒng)類加載器(也稱AppClassLoader// 應(yīng)用程序類加載器)加載 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} } // 從Web應(yīng)用程序的類加載器(也就是WebappClassLoader)中加載類。Web應(yīng)用程序的類加載器是// 一個(gè)特殊的類加載器,它負(fù)責(zé)從Web應(yīng)用程序的本地庫(kù)中加載類 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 } // 經(jīng)過(guò)上面幾個(gè)步驟還未加載到類,則采用系統(tǒng)類加載器(也稱應(yīng)用程序類加載器)進(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} }}// 最終,還未加載到類,報(bào)類未找到的異常throw new ClassNotFoundException(name); }//...省略不需要關(guān)注的代碼}

綜上所述,我們得出WebappClassLoader類加載器打破了雙親委派機(jī)制,自定義類加載類的順序:

擴(kuò)展類加載器(ExtClassLoader)加載Web應(yīng)用程序類加載器(WebappClassLoader)系統(tǒng)類加載器類(AppClassLoader)公共類加載器類(CommonClassLoader)

如果Web應(yīng)用程序類加載器配置為,,也就是WebappClassLoaderBase類的變量delegate=true時(shí),則類加載順序變?yōu)椋?/p>擴(kuò)展類加載器(ExtClassLoader)加載系統(tǒng)類加載器類(AppClassLoader)公共類加載器類(CommonClassLoader)Web應(yīng)用程序類加載器(WebappClassLoader)JSP類加載器(JasperLoader)

上代碼:

public class JasperLoader extends URLClassLoader { private final PermissionCollection permissionCollection; private final SecurityManager securityManager; // JSP類加載器的父加載器是Web應(yīng)用程序類加載器(WebappClassLoader) public JasperLoader(URL[] urls, ClassLoader parent,PermissionCollection permissionCollection) {super(urls, parent);this.permissionCollection = permissionCollection;this.securityManager = System.getSecurityManager(); } @Override public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false); } @Override public synchronized Class<?> loadClass(final String name, boolean resolve)throws ClassNotFoundException {Class<?> clazz = null;// 從JVM的類緩存中查找clazz = findLoadedClass(name);if (clazz != null) { if (resolve) {resolveClass(clazz); } return clazz;}// 當(dāng)使用SecurityManager安全管理器時(shí),允許訪問(wèn)訪類if (securityManager != null) { int dot = name.lastIndexOf('.'); if (dot >= 0) {try { // Do not call the security manager since by default, we grant that package. if (!'org.apache.jasper.runtime'.equalsIgnoreCase(name.substring(0,dot))){securityManager.checkPackageAccess(name.substring(0,dot)); }} catch (SecurityException se) { String error = 'Security Violation, attempt to use ' +'Restricted Class: ' + name; se.printStackTrace(); throw new ClassNotFoundException(error);} }} // 如果類名不是以org.apache.jsp包名開(kāi)頭的,則采用WebappClassLoader加載if( !name.startsWith(Constants.JSP_PACKAGE_NAME + '.') ) { // Class is not in org.apache.jsp, therefore, have our // parent load it clazz = getParent().loadClass(name); if( resolve ) {resolveClass(clazz); } return clazz;}// 如果是org.apache.jsp包名開(kāi)頭JSP類,就調(diào)用父類URLClassLoader的findClass方法// 動(dòng)態(tài)加載類文件,解析成Class類,返回給調(diào)用方return findClass(name); }}

下面是URLClassLoader的findClass方法,具體實(shí)現(xiàn):

protected Class<?> findClass(final String name)throws ClassNotFoundException {final Class<?> result;try { result = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() { public Class<?> run() throws ClassNotFoundException {String path = name.replace('.', '/').concat('.class');Resource res = ucp.getResource(path, false);if (res != null) { try { // 解析類的字節(jié)碼文件生成Class類對(duì)象return defineClass(name, res); } catch (IOException e) {throw new ClassNotFoundException(name, e); }} else { return null;} }}, acc);} catch (java.security.PrivilegedActionException pae) { throw (ClassNotFoundException) pae.getException();}if (result == null) { throw new ClassNotFoundException(name);}return result; }

從源碼中我們可以看到,JSP類加載原理是,先從JVM類緩存中(也就是Bootstrap類加載器加載的類)加載,如果不是核心類庫(kù)的類,就從Web應(yīng)用程序類加載器WebappClassLoader中加載,如果還未找到,就說(shuō)明是jsp類,則通過(guò)動(dòng)態(tài)解析jsp類文件獲得要加載的類。

經(jīng)過(guò)上面兩個(gè)Tomcat核心類加載器的剖析,我們也就知道了Tomcat類的加載原理了。

下面我們來(lái)總結(jié)一下:Tomcat會(huì)為每個(gè)Web應(yīng)用程序創(chuàng)建一個(gè)WebappClassLoader類加載器進(jìn)行類的加載,不同的類加載器實(shí)例加載的類是會(huì)被認(rèn)為是不同的類,即使它們的類名相同,這樣的話就可以實(shí)現(xiàn)在同一個(gè)JVM下,允許Tomcat容器的不同部分以及在容器上運(yùn)行的不同Web應(yīng)用程序可以訪問(wèn)的各種不同版本的類庫(kù)。

針對(duì)JSP類,會(huì)由專門(mén)的JSP類加載器(JasperLoader)進(jìn)行加載,該加載器會(huì)針對(duì)JSP類在每次加載時(shí)都會(huì)解析類文件,Tomcat容器會(huì)啟動(dòng)一個(gè)后臺(tái)線程,定時(shí)檢測(cè)JSP類文件的變化,及時(shí)更新類文件,這樣就實(shí)現(xiàn)JSP文件的熱加載功能。

以上就是源碼剖析Tomcat類的加載原理的詳細(xì)內(nèi)容,更多關(guān)于Tomcat類加載的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Tomcat
主站蜘蛛池模板: 纯化水设备-纯水设备-超纯水设备-[大鹏水处理]纯水设备一站式服务商-东莞市大鹏水处理科技有限公司 | 电动车头盔厂家_赠品头盔_安全帽批发_山东摩托车头盔—临沂承福头盔 | 高压油管,液压接头,液压附件-烟台市正诚液压附件 | 液压压力机,液压折弯机,液压剪板机,模锻液压机-鲁南新力机床有限公司 | 智能交通网_智能交通系统_ITS_交通监控_卫星导航_智能交通行业 | 工业风机_环保空调_冷风机_工厂车间厂房通风降温设备旺成服务平台 | 电地暖-电采暖-发热膜-石墨烯电热膜品牌加盟-暖季地暖厂家 | 二维运动混料机,加热型混料机,干粉混料机-南京腾阳干燥设备厂 | 网站优化公司_北京网站优化_抖音短视频代运营_抖音关键词seo优化排名-通则达网络 | 对夹式止回阀_对夹式蝶形止回阀_对夹式软密封止回阀_超薄型止回阀_不锈钢底阀-温州上炬阀门科技有限公司 | 哲力实业_专注汽车涂料汽车漆研发生产_汽车漆|修补油漆品牌厂家 长沙一级消防工程公司_智能化弱电_机电安装_亮化工程专业施工承包_湖南公共安全工程有限公司 | 天津试验仪器-电液伺服万能材料试验机,恒温恒湿标准养护箱,水泥恒应力压力试验机-天津鑫高伟业科技有限公司 | 单机除尘器 骨架-脉冲除尘器设备生产厂家-润天环保设备 | 特种电缆厂家-硅橡胶耐高温电缆-耐低温补偿导线-安徽万邦特种电缆有限公司 | 铆钉机|旋铆机|东莞旋铆机厂家|鸿佰专业生产气压/油压/自动铆钉机 | 工业制氮机_psa制氮机厂家-宏骁智能装备科技江苏有限公司 | 华夏医界网_民营医疗产业信息平台_民营医院营销管理培训 | 合景一建-无尘车间设计施工_食品医药洁净车间工程装修总承包公司 | 欧洲MV日韩MV国产_人妻无码一区二区三区免费_少妇被 到高潮喷出白浆av_精品少妇自慰到喷水AV网站 | 科箭WMS仓库管理软件-TMS物流管理系统-科箭SaaS云服务 | 阴离子_阳离子聚丙烯酰胺厂家_聚合氯化铝价格_水处理絮凝剂_巩义市江源净水材料有限公司 | 成人纸尿裤,成人尿不湿,成人护理垫-山东康舜日用品有限公司 | YAGEO国巨电容|贴片电阻|电容价格|三星代理商-深圳市巨优电子有限公司 | 胃口福饺子加盟官网_新鲜现包饺子云吞加盟 - 【胃口福唯一官网】 | 协议书_协议合同格式模板范本大全| 蓄电池在线监测系统|SF6在线监控泄露报警系统-武汉中电通电力设备有限公司 | 范秘书_懂你的范文小秘书| 拉力机-拉力试验机-万能试验机-电子拉力机-拉伸试验机-剥离强度试验机-苏州皖仪实验仪器有限公司 | 防腐木批发价格_深圳_惠州_东莞防腐木厂家_森源(深圳)防腐木有限公司 | 电子元器件呆滞料_元器件临期库存清仓尾料_尾料优选现货采购处理交易商城 | 强效碱性清洗剂-实验室中性清洗剂-食品级高纯氮气发生器-上海润榕科学器材有限公司 | 汽液过滤网厂家_安平县银锐丝网有限公司| 济南电缆桥架|山东桥架-济南航丰实业有限公司 | 无菌检查集菌仪,微生物限度仪器-苏州长留仪器百科 | 环氧乙烷灭菌器_压力蒸汽灭菌器_低温等离子过氧化氢灭菌器 _低温蒸汽甲醛灭菌器_清洗工作站_医用干燥柜_灭菌耗材-环氧乙烷灭菌器_脉动真空压力蒸汽灭菌器_低温等离子灭菌设备_河南省三强医疗器械有限责任公司 | 标策网-专注公司商业知识服务、助力企业发展| 泰国试管婴儿_泰国第三代试管婴儿费用|成功率|医院—新生代海外医疗 | 工业废水处理|污水处理厂|废水治理设备工程技术公司-苏州瑞美迪 今日娱乐圈——影视剧集_八卦娱乐_明星八卦_最新娱乐八卦新闻 | 篮球地板厂家_舞台木地板品牌_体育运动地板厂家_凯洁地板 | 长沙网站建设制作「网站优化推广」-网页设计公司-速马科技官网 | 常州翔天实验仪器厂-恒温振荡器-台式恒温振荡器-微量血液离心机 恒温恒湿箱(药品/保健品/食品/半导体/细菌)-兰贝石(北京)科技有限公司 |