色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

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

源碼剖析Tomcat類的加載原理

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

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

然而與許多服務器應用程序一樣,Tomcat 允許容器的不同部分以及在容器上運行的不同Web應用程序可以訪問的各種不同版本的類庫,這就要求Tomcat必須打破這種雙親委派機制,通過實現(xiàn)自定義的類加載器(即實現(xiàn)了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中實現(xiàn)的類加載方法loadClass

public abstract class WebappClassLoaderBase extends URLClassLoaderimplements Lifecycle, InstrumentableClassLoader, WebappProperties, PermissionCheck {//...省略不需要關(guān)注的代碼 protected WebappClassLoaderBase() {super(new URL[0]);// 獲取當前WebappClassLoader的父加載器系統(tǒng)類加載器ClassLoader p = getParent();if (p == null) { p = getSystemClassLoader();}this.parent = p;// javaseClassLoader變量經(jīng)過以下代碼的執(zhí)行,// 得到的是擴展類加載器(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應用程序停止狀態(tài)時,不允許加載新的類 checkStateForClassLoading(name); // 如果之前加載過該類,就可以從Web應用程序類加載器本地類緩存中查找,// 如果找到說明WebappClassLoader之前已經(jīng)加載過這個類 clazz = findLoadedClass0(name); if (clazz != null) {if (log.isDebugEnabled()) { log.debug(' Returning class from cache');}if (resolve) { resolveClass(clazz);}return clazz; } // Web應用程序本地類緩存中沒有,可以從系統(tǒng)類加載器緩存中查找,// 如果找到說明AppClassLoader之前已經(jīng)加載過這個類 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);// 獲取引導類加載器(BootstrapClassLoader) ClassLoader javaseLoader = getJavaseClassLoader(); boolean tryLoadingFromJavaseLoader; try { // 引導類加載器根據(jù)轉(zhuǎn)換后的類名獲取資源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 容器部分的實現(xiàn)。 * catalina-ant.jar — 可選。用于使用 Manager Web 應用程序的 Tomcat Catalina Ant 任務。 * catalina-ha.jar — 可選。提供基于 Tribes 構(gòu)建的會話集群功能的高可用性包。 * catalina-storeconfig.jar — 可選。從當前狀態(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 編譯器和運行時。 * jasper-el.jar — 可選。Tomcat EL 實現(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 定義的幾個接口。 * tomcat-coyote.jar — Tomcat 連接器和實用程序類。 * tomcat-dbcp.jar — 可選。基于 Apache Commons Pool 2 和 Apache Commons DBCP 2 的 * 包重命名副本的數(shù)據(jù)庫連接池實現(xiàn)。 * tomcat-i18n-**.jar — 包含其他語言資源包的可選 JAR。由于默認包也包含在每個單獨的JAR * 中,如果不需要消息國際化,可以安全地刪除它們。 * tomcat-jdbc.jar — 可選。另一種數(shù)據(jù)庫連接池實現(xiàn),稱為 Tomcat JDBC 池。有關(guān)詳細信息,請參閱 文檔。 * tomcat-jni.jar — 提供與 Tomcat Native 庫的集成。 * tomcat-util.jar — Apache Tomcat 的各種組件使用的通用類。 * tomcat-util-scan.jar — 提供 Tomcat 使用的類掃描功能。 * tomcat-websocket.jar — 可選。Java WebSocket 1.1 實現(xiàn) * websocket-api.jar — 可選。Java WebSocket 1.1 API * * 此處的filter方法,實際上tomcat官方將filter類加載過濾條件,看作是一種類加載器, *將其取名為CommonClassLoader */ boolean delegateLoad = delegate || filter(name, true); // 如果ExtClassLoader沒有獲取到,說明是非JRE核心類,那么就從系統(tǒng)類加載器(也稱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 } // 經(jīng)過上面幾個步驟還未加載到類,則采用系統(tǒng)類加載器(也稱應用程序類加載器)進行加載 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); }//...省略不需要關(guān)注的代碼}

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

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

如果Web應用程序類加載器配置為,,也就是WebappClassLoaderBase類的變量delegate=true時,則類加載順序變?yōu)椋?/p>擴展類加載器(ExtClassLoader)加載系統(tǒng)類加載器類(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類,就調(diào)用父類URLClassLoader的findClass方法// 動態(tài)加載類文件,解析成Class類,返回給調(diào)用方return findClass(name); }}

下面是URLClassLoader的findClass方法,具體實現(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類對象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類,則通過動態(tài)解析jsp類文件獲得要加載的類。

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

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

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

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

標簽: Tomcat
主站蜘蛛池模板: 新久草视频 | 欧美xxxx4khd超高清 | 免费精品国产日韩热久久 | 9lporm自拍视频在线 | 热99re久久国超精品首页 | 国产色手机在线观看播放 | 亚洲免费人成在线视频观看 | 91国在线观看| 日韩中文在线观看 | 久久精品综合免费观看 | 欧美成人福利 | 欧美精品成人 | 亚洲观看视频 | 国产高清成人mv在线观看 | 久草在线观看福利 | 亚洲免费在线观看 | 免费观看一级成人毛片 | 欧美一级毛片片免费 | 久久久久久国产精品免费 | 男女在线视频 | 国产成人福利夜色影视 | 久久精品国产第一区二区 | 日本在线观看免费视频网址 | 久久依人 | 9999毛片免费看 | 亚洲毛片免费观看 | 国产成人欧美视频在线 | 99日韩| 久久影院在线观看 | 亚洲在线第一页 | 国产日韩精品欧美一区喷 | 日本高清va不卡视频在线观看 | 亚洲骚片 | 亚洲综合色一区二区三区小说 | 成人午夜在线观看国产 | 久久国产情侣 | 在线观看免费视频网站色 | 日韩专区亚洲精品欧美专区 | 222aaa天堂| 中文字幕或区 | 99热精品在线免费观看 |