日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

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

源碼剖析Tomcat類的加載原理

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

眾所周知,Java中默認的類加載器是以父子關系存在的,實現了雙親委派機制進行類的加載,在前文中,我們提到了,雙親委派機制的設計是為了保證類的唯一性,這意味著在同一個JVM中是不能加載相同類庫的不同版本的類。

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

Tomcat中有兩個最重要的類加載器,第一個便是負責Web應用程序類加載的WebappClassLoader,另一個便是JSP Servlet類加載器`JasperLoader。

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

上代碼:

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

我們來看看WebappClassLoader繼承的WebappClassLoaderBase中實現的類加載方法loadClass

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

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

擴展類加載器(ExtClassLoader)加載Web應用程序類加載器(WebappClassLoader)系統類加載器類(AppClassLoader)公共類加載器類(CommonClassLoader)

如果Web應用程序類加載器配置為,,也就是WebappClassLoaderBase類的變量delegate=true時,則類加載順序變為:

擴展類加載器(ExtClassLoader)加載系統類加載器類(AppClassLoader)公共類加載器類(CommonClassLoader)Web應用程序類加載器(WebappClassLoader)JSP類加載器(JasperLoader)

上代碼:

public class JasperLoader extends URLClassLoader { private final PermissionCollection permissionCollection; private final SecurityManager securityManager; // JSP類加載器的父加載器是Web應用程序類加載器(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;}// 當使用SecurityManager安全管理器時,允許訪問訪類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包名開頭的,則采用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包名開頭JSP類,就調用父類URLClassLoader的findClass方法// 動態加載類文件,解析成Class類,返回給調用方return findClass(name); }}

下面是URLClassLoader的findClass方法,具體實現:

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 { // 解析類的字節碼文件生成Class類對象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類加載器加載的類)加載,如果不是核心類庫的類,就從Web應用程序類加載器WebappClassLoader中加載,如果還未找到,就說明是jsp類,則通過動態解析jsp類文件獲得要加載的類。

經過上面兩個Tomcat核心類加載器的剖析,我們也就知道了Tomcat類的加載原理了。

下面我們來總結一下:Tomcat會為每個Web應用程序創建一個WebappClassLoader類加載器進行類的加載,不同的類加載器實例加載的類是會被認為是不同的類,即使它們的類名相同,這樣的話就可以實現在同一個JVM下,允許Tomcat容器的不同部分以及在容器上運行的不同Web應用程序可以訪問的各種不同版本的類庫。

針對JSP類,會由專門的JSP類加載器(JasperLoader)進行加載,該加載器會針對JSP類在每次加載時都會解析類文件,Tomcat容器會啟動一個后臺線程,定時檢測JSP類文件的變化,及時更新類文件,這樣就實現JSP文件的熱加載功能。

以上就是源碼剖析Tomcat類的加載原理的詳細內容,更多關于Tomcat類加載的資料請關注好吧啦網其它相關文章!

標簽: Tomcat
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲v在线看| 日韩欧美综合| 激情久久中文字幕| 亚洲婷婷在线| 欧美国产另类| 国产精品亚洲一区二区三区在线观看| 老司机精品久久| 偷拍欧美精品| 精品国产亚洲一区二区三区在线 | 91精品啪在线观看国产18| 免费视频最近日韩| av亚洲一区二区三区| 亚洲毛片一区| 日韩视频久久| 日韩国产一区| 国产一区二区三区精品在线观看| 精品丝袜久久| 久久精品一区二区国产| 国产精品视频3p| 性色一区二区| 日韩影院免费视频| 亚洲精品自拍| 老牛国内精品亚洲成av人片| 日韩精品看片| 亚洲一区免费| 中文欧美日韩| 亚洲免费专区| 欧美黄色一区| 日本亚洲最大的色成网站www | 日本伊人久久| 国产九一精品| 亚洲风情在线资源| 免费视频亚洲| 国产三级一区| 日韩高清中文字幕一区二区| 亚洲网址在线观看| 日韩动漫一区| 国产精品成人一区二区不卡| 国产精品美女| 国产66精品| 亚洲成人一区| 久久激情五月婷婷| 久久国产欧美| 中国女人久久久| 久久99久久久精品欧美| 亚洲福利一区| 日韩福利视频导航| 你懂的网址国产 欧美| 国内精品福利| 国产精品久久久亚洲一区| 欧美国产日韩电影| 国产精品成人3p一区二区三区| 中文字幕在线看片| 亚洲精一区二区三区| 欧美福利在线| 久久字幕精品一区| 免费成人在线观看| 日韩欧美在线中字| 亚洲精品123区| 精品理论电影在线| 日韩三区免费| 国产精品久久久久久久久久白浆| 免费日韩av片| 不卡视频在线| 青青国产精品| 亚洲黄色在线| 国产精品网址| 一区二区亚洲视频| 麻豆精品一区二区综合av| 久久精品国产www456c0m| 九九九精品视频| 免费在线亚洲| 国产欧美日韩一级| 日韩成人精品一区二区| 国产成人黄色| 日韩有吗在线观看| 激情欧美一区二区三区| 成人午夜毛片| 狠狠久久伊人中文字幕| 国产精品115| 日韩av不卡在线观看| 中文字幕系列一区| 亚洲午夜免费| 国产精品色婷婷在线观看| 欧美成人精品午夜一区二区| 久久久精品区| 成人自拍av| 香蕉久久精品| 日韩中文字幕91| 日韩三级精品| 麻豆一区在线| 欧美a一区二区| 欧美综合另类| 日韩va亚洲va欧美va久久| 国产精品亚洲人成在99www| 男人天堂欧美日韩| 99视频精品全国免费| av高清一区| 亚洲精品激情| 久久精品av麻豆的观看方式| 丰满少妇一区| 国产成人精品一区二区三区视频| 欧美三级精品| 夜夜精品视频| 日韩在线欧美| 欧美 日韩 国产一区二区在线视频 | 日本亚洲欧洲无免费码在线| 国产欧美激情| 国产+成+人+亚洲欧洲在线| 国产麻豆综合| 欧美视频一区| 欧美国产日本| 美女国产精品久久久| 综合激情婷婷| 欧美午夜精彩| 一区在线免费观看| 国产 日韩 欧美 综合 一区| 免费在线小视频| 久久三级中文| 国产一区二区三区探花| 国产日韩欧美一区在线| 麻豆中文一区二区| 国产69精品久久| 成人在线免费观看91| 日韩激情av在线| 蜜桃av一区二区| 性欧美69xoxoxoxo| 天堂久久一区| 好吊视频一区二区三区四区| 日韩精品不卡一区二区| 青青伊人久久| 亚洲我射av| 午夜精品婷婷| 欧美大黑bbbbbbbbb在线| 久久青青视频| 国产日韩欧美一区二区三区| 日韩动漫一区| 亚洲欧美日韩在线观看a三区| 秋霞影视一区二区三区| 老司机免费视频一区二区| 欧美日韩国产一区精品一区| 久久久久美女| 五月天激情综合网| 老司机久久99久久精品播放免费| 欧美专区18| 最新国产拍偷乱拍精品| 国产成人精品一区二区三区免费 | 蜜臀av性久久久久蜜臀aⅴ四虎| 私拍精品福利视频在线一区| 精品国产一区二区三区噜噜噜| 欧美激情网址| 久久不射网站| 欧美日韩国产高清电影| 欧美日韩精品免费观看视完整| 国产精品久久久久av电视剧| 女同性一区二区三区人了人一| 亚洲欧美不卡| 国产午夜久久av| 日韩欧美激情电影| 97精品资源在线观看| 国产欧美69| 国产情侣一区在线| 精品中文在线| 激情黄产视频在线免费观看| 99成人在线| 日韩三区四区| 日本在线视频一区二区| 久久精品免视看国产成人| 视频小说一区二区| 国产精品xxx| 精品一区二区三区亚洲| 日韩欧美精品一区| 国产精品丝袜在线播放| 国产福利资源一区| 麻豆一区二区三| 综合日韩av| 久久一区二区三区喷水| 免费观看在线综合色| 婷婷亚洲成人| 国产在线|日韩| 日本综合字幕| 久久婷婷一区| 久久gogo国模啪啪裸体| 香蕉久久99| 国产亚洲欧美日韩在线观看一区二区 | 日韩欧美视频专区| 青青草精品视频| 97精品中文字幕| 日本综合精品一区| 在线观看精品| 国产伦精品一区二区三区千人斩| 一区在线免费观看| 国产 日韩 欧美一区| 欧美1区免费| 蜜臀av一区二区三区| 日本国产欧美| 黄毛片在线观看| 免费精品视频最新在线| 视频一区二区三区入口| 国产精品日韩精品在线播放|