婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Tomcat 類加載器的實現方法及實例代碼

Tomcat 類加載器的實現方法及實例代碼

熱門標簽:金融行業外呼線路 百度地圖標注要不要錢 高德地圖標注無營業執照 賀州市地圖標注app 長沙開福怎么申請400電話 東莞人工智能電銷機器人供應商 智能電話機器人線路 廣州電銷機器人系統圖 江蘇電銷外呼防封系統是什么

Tomcat 內部定義了多個 ClassLoader,以便應用和容器訪問不同存儲庫中的類和資源,同時達到應用間類隔離的目的。

1. Java 類加載機制

類加載就是把編譯生成的 class 文件,加載到 JVM 內存中(永久代/元空間)。

類加載器之所以能實現類隔離,是因為兩個類相等的前提是它們由同一個類加載器加載,否則必定不相等。

JVM 在加載時,采用的是一種雙親委托機制,當類加載器要加載一個類時,加載順序是:

首先將請求委托給父加載器,如果父加載器找不到要加載的類然后再查找自己的存儲庫嘗試加載

這個機制的好處就是能夠保證核心類庫不被覆蓋。

而按照 Servlet 規范的建議,Webapp 加載器略有不同,它首先會在自己的資源庫中搜索,而不是向上委托,打破了標準的委托機制,來看下 Tomcat 的設計和實現。

2. Tomcat 類加載器設計

Tomcat 整體類加載器結構如下:

其中 JDK 內部提供的類加載器分別是:

Bootstrap - 啟動類加載器,屬于 JVM 的一部分,加載 <JAVA_HOME>/lib/ 目錄下特定的文件Extension - 擴展類加載器,加載 <JAVA_HOME>/lib/ext/ 目錄下的類庫Application - 應用程序類加載器,也叫系統類加載器,加載 CLASSPATH 指定的類庫

Tomcat 自定義實現的類加載器分別是:

Common - 父加載器是 AppClassLoader,默認加載 ${catalina.home}/lib/ 目錄下的類庫Catalina - 父加載器是 Common 類加載器,加載 catalina.properties 配置文件中 server.loader 配置的資源,一般是 Tomcat 內部使用的資源Shared - 父加載器是 Common 類加載器,加載 catalina.properties 配置文件中 shared.loader 配置的資源,一般是所有 Web 應用共享的資源WebappX - 父加載器是 Shared 加載器,加載 /WEB-INF/classes 的 class 和 /WEB-INF/lib/ 中的 jar 包JasperLoader - 父加載器是 Webapp 加載器,加載 work 目錄應用編譯 JSP 生成的 class 文件

在實現時,上圖不是繼承關系,而是通過組合體現父子關系。Tomcat 類加載器的源碼類圖:

Common、Catalina 、Shared 它們都是 StandardClassLoader 的實例,在默認情況下,它們引用的是同一個對象。其中 StandardClassLoader 與 URLClassLoader 沒有區別;WebappClassLoader 則按規范實現以下順序的查找并加載:

從 JVM 內部的 Bootstrap 倉庫加載從應用程序加載器路徑,即 CLASSPATH 下加載從 Web 程序內的 /WEB-INF/classes 目錄從 Web 程序內的 /WEB-INF/lib 中的 jar 文件從容器 Common 加載器倉庫,即所有 Web 程序共享的資源加載

接下來看下源碼實現。

3. 自定義加載器的初始化

common 類加載器是在 Bootstrap 的 initClassLoaders 初始化的,源碼如下:

private void initClassLoaders() {
 try {
 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();
 }
 // 指定倉庫路徑配置文件前綴和父加載器,創建 ClassLoader 實例
 catalinaLoader = createClassLoader("server", commonLoader);
 sharedLoader = createClassLoader("shared", commonLoader);
 } catch (Throwable t) {
 log.error("Class loader creation threw exception", t);
 System.exit(1);
 }
}

可以看到分別創建了三個類加載器,createClassLoader 就是根據配置獲取資源倉庫地址,最后返回一個 StandardClassLoader 實例,核心代碼如下:

private ClassLoader createClassLoader(String name, ClassLoader parent)
 throws Exception {

 String value = CatalinaProperties.getProperty(name + ".loader");
 if ((value == null) || (value.equals("")))
  return parent; // 如果沒有配置,則返回傳入的父加載器
 ArrayList repositoryLocations = new ArrayList();
 ArrayList repositoryTypes = new ArrayList();
 ...
 // 獲取資源倉庫路徑
 String[] locations = (String[]) repositoryLocations.toArray(new String[0]);
 Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]);
 // 創建一個 StandardClassLoader 對象
 ClassLoader classLoader = ClassLoaderFactory.createClassLoader
   (locations, types, parent);
 ...
 return classLoader;
}

類加載器初始化完畢后,會創建一個 Catalina 對象,最終會調用它的 load 方法,解析 server.xml 初始化容器內部組件。那么容器,比如 Engine,又是怎么關聯到這個設置的父加載器的呢?

Catalina 對象有一個 parentClassLoader 成員變量,它是所有組件的父加載器,默認是 AppClassLoader,在此對象創建完畢時,會反射調用它的 setParentClassLoader 方法,將父加載器設為 sharedLoader。

而 Tomcat 內部頂級容器 Engine 在初始化時,Digester 有一個 SetParentClassLoaderRule 規則,會將 Catalina 的 parentClassLoader 通過 Engine.setParentClassLoader 方法關聯起來。

4. 如何打破雙親委托機制

答案是使用 Thread.getContextClassLoader() - 當前線程的上下文加載器,該加載器可通過 Thread.setContextClassLoader() 在代碼運行時動態設置。

默認情況下,Thread 上下文加載器繼承自父線程,也就是說所有線程默認上下文加載器都與第一個啟動的線程相同,也就是 main 線程,它的上下文加載器是 AppClassLoader。

Tomcat 就是在 StandardContext 啟動時首先初始化一個 WebappClassLoader 然后設置為當前線程的上下文加載器,最后將其封裝為 Loader 對象,借助容器之間的父子關系,在加載 Servlet 類時使用。

5. Web 應用的類加載

Web 應用的類加載是由 WebappClassLoader 的方法 loadClass(String, boolean) 完成,核心代碼如下:

在防止覆蓋 J2SE

public synchronized Class loadClass(String name, boolean resolve)
 throws ClassNotFoundException {
 ...
 Class clazz = null;
 // (0) 檢查自身內部緩存中是否已經加載
 clazz = findLoadedClass0(name);
 if (clazz != null) {
 if (log.isDebugEnabled())
  log.debug(" Returning class from cache");
 if (resolve) resolveClass(clazz);
 return (clazz);
 }
 // (0.1) 檢查 JVM 的緩存中是否已經加載
 clazz = findLoadedClass(name);
 if (clazz != null) {
 if (log.isDebugEnabled())
  log.debug(" Returning class from cache");
 if (resolve) resolveClass(clazz);
 return (clazz);
 }
 // (0.2) 嘗試使用系統類加載加載,防止覆蓋 J2SE 類
 try {
 clazz = system.loadClass(name);
 if (clazz != null) {
  if (resolve) resolveClass(clazz);
  return (clazz);
 }
 } catch (ClassNotFoundException e) {// Ignore}
 // (0.5) 使用 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);
 // (1) 是否委托給父類,這里默認為 false
 if (delegateLoad) {
  ...
 }
 // (2) 嘗試查找自己的存儲庫并加載
 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) {}
 // (3) 如果此時還加載失敗,那么將加載請求委托給父加載器
 if (!delegateLoad) {
 if (log.isDebugEnabled())
  log.debug(" Delegating to parent classloader at end: " + parent);
 ClassLoader loader = parent;
 if (loader == null)
  loader = system;
 try {
  clazz = loader.loadClass(name);
  if (clazz != null) {
  if (log.isDebugEnabled())
   log.debug(" Loading class from parent");
  if (resolve) resolveClass(clazz);
  return (clazz);
  }
 } catch (ClassNotFoundException e) {}
 }
 // 最后加載失敗,拋出異常
 throw new ClassNotFoundException(name);
}

在防止覆蓋 J2SE 類的時候,版本 Tomcat 6,使用的是 AppClassLoader,rt.jar 核心類庫是由 Bootstrap Classloader 加載的,但是在 Java 代碼是獲取不了這個加載器的,在高版本做了以下優化:
ClassLoader j = String.class.getClassLoader();
if (j == null) {
 j = getSystemClassLoader();
 while (j.getParent() != null) {
 j = j.getParent();
 }
}
this.javaseClassLoader = j;

類的時候,版本 Tomcat 6,使用的是 AppClassLoader,rt.jar 核心類庫是由 Bootstrap Classloader 加載的,但是在 Java 代碼是獲取不了這個加載器的,在高版本做了以下優化:

ClassLoader j = String.class.getClassLoader();
if (j == null) {
 j = getSystemClassLoader();
 while (j.getParent() != null) {
 j = j.getParent();
 }
}
this.javaseClassLoader = j;

也就是使用盡可能接近 Bootstrap 加載器的類加載器。

6. 小結

相信大部分人都遇到過 ClassNotFoundException 這個異常,這背后就涉及到了類加載器,對加載的原理有一定的了解,有助于排查問題。

以上所述是小編給大家介紹的Tomcat 類加載器的實現方法及實例代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

標簽:張家界 洛陽 廊坊 玉樹 滄州 永州 松原 北京

巨人網絡通訊聲明:本文標題《Tomcat 類加載器的實現方法及實例代碼》,本文關鍵詞  Tomcat,類,加載,器,的,實現,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Tomcat 類加載器的實現方法及實例代碼》相關的同類信息!
  • 本頁收集關于Tomcat 類加載器的實現方法及實例代碼的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    久久www免费人成看片高清| 欧美日本在线一区| 韩国毛片一区二区三区| 日本伊人午夜精品| 奇米888四色在线精品| 午夜欧美大尺度福利影院在线看| 亚洲图片欧美激情| 亚洲精品高清在线观看| 亚洲视频一区在线观看| 亚洲欧美综合色| 亚洲综合在线视频| 日韩av在线免费观看不卡| 蜜臀av性久久久久蜜臀aⅴ四虎| 日韩中文字幕区一区有砖一区 | 国产成人免费视频| 国产91精品免费| 国产一区二区三区电影在线观看| 亚洲成年人影院| 美国av一区二区| 国产成人亚洲综合色影视| 91亚洲永久精品| 欧美日韩一级黄| 日韩欧美在线网站| 国产欧美一区二区三区鸳鸯浴| 国产高清无密码一区二区三区| 国产成人亚洲精品青草天美 | 日韩一区二区三区视频在线观看| 日韩欧美成人一区二区| 久久婷婷国产综合国色天香| 国产精品每日更新| 一区二区三区中文在线| 午夜久久久久久电影| 精油按摩中文字幕久久| 欧美一区二区美女| 欧美一区二区日韩| 中文字幕精品在线不卡| 亚洲成a人在线观看| 成人综合在线视频| 欧美精品丝袜中出| 国产精品久久久久影院老司| 午夜国产精品一区| 成人午夜电影小说| 欧美一区二区三区成人| 国产精品伦理在线| 老司机精品视频线观看86| 色综合天天视频在线观看| 2021国产精品久久精品| 亚洲另类中文字| 国产精品538一区二区在线| 色视频一区二区| 欧美国产精品专区| 久久er99精品| 欧美精品久久天天躁| 中文字幕一区二区三区不卡| 韩国三级电影一区二区| 欧美精品 日韩| 亚洲一区二区成人在线观看| voyeur盗摄精品| 国产午夜精品一区二区三区嫩草 | 国产米奇在线777精品观看| 欧美日韩另类一区| 亚洲丝袜美腿综合| 国v精品久久久网| 欧美tickling挠脚心丨vk| 日韩福利视频网| 欧美三日本三级三级在线播放| 中文字幕一区日韩精品欧美| 国产乱人伦偷精品视频免下载| 欧美精品日日鲁夜夜添| 亚洲第四色夜色| 欧美三级韩国三级日本三斤| 亚洲男人电影天堂| 91老司机福利 在线| 亚洲乱码中文字幕综合| 色综合色综合色综合色综合色综合| 国产色婷婷亚洲99精品小说| 性久久久久久久| 国产美女av一区二区三区| 91精品国产一区二区三区蜜臀 | 久久国内精品视频| 午夜一区二区三区视频| www.亚洲色图.com| 久久久久久久网| 日本美女视频一区二区| 欧美系列日韩一区| 亚洲乱码中文字幕综合| 97se亚洲国产综合在线| 中文字幕电影一区| 国产一区二区福利视频| 26uuu国产电影一区二区| 久久成人18免费观看| 日韩限制级电影在线观看| 偷拍自拍另类欧美| 久久综合色8888| 成a人片国产精品| 一区二区免费在线| 欧美一区二区三区在线看| 久久99蜜桃精品| 国产欧美日韩麻豆91| 在线一区二区观看| 轻轻草成人在线| 国产亚洲精品7777| 欧美少妇bbb| 国产在线精品一区在线观看麻豆| 国产精品免费丝袜| 欧美精品 国产精品| 丁香六月综合激情| 亚洲成人av中文| 国产精品对白交换视频| 欧美日韩精品一区二区天天拍小说 | 日韩免费视频一区| 国产99精品国产| 偷拍与自拍一区| 国产精品区一区二区三区| 欧美三级午夜理伦三级中视频| 国产一区二区三区久久悠悠色av | 国产成人在线视频免费播放| 亚洲精品国产精品乱码不99| 欧美va日韩va| 欧美日韩一区二区三区视频| 国产成人av电影免费在线观看| 亚洲成av人影院| 中文字幕日韩一区| 久久亚洲精精品中文字幕早川悠里 | 欧美视频第二页| 国产成人精品免费在线| 日本美女一区二区三区视频| 亚洲激情成人在线| 国产精品视频一二| 精品88久久久久88久久久| 欧美久久久影院| 欧美午夜一区二区三区免费大片| 国产福利一区在线观看| 丁香激情综合五月| 亚洲精品成人精品456| 日韩一区二区三区视频| 成人午夜精品一区二区三区| 亚洲综合无码一区二区| 欧美videofree性高清杂交| 成人黄页在线观看| 亚洲h动漫在线| 欧美精品一区二区三区蜜臀| av在线播放不卡| 日韩一区二区免费电影| 国产成人午夜精品5599| 亚洲男人的天堂av| 亚洲精品一区二区三区蜜桃下载 | 制服丝袜一区二区三区| 国产在线视频精品一区| 一区二区三区美女视频| 91天堂素人约啪| 色天天综合色天天久久| 欧美在线观看视频在线| 欧美日韩高清在线播放| 欧美乱熟臀69xxxxxx| 91精品欧美综合在线观看最新| 欧美一级爆毛片| 26uuu久久天堂性欧美| 国产欧美视频一区二区| 亚洲天堂免费看| 一区二区三区欧美日| 视频一区二区三区入口| 欧美bbbbb| 国产91精品欧美| 91精品办公室少妇高潮对白| 欧美日免费三级在线| 日韩欧美一区二区不卡| 久久综合久久综合久久| 欧美国产亚洲另类动漫| 亚洲男同1069视频| 另类小说综合欧美亚洲| 成人精品免费看| 欧美在线制服丝袜| 日韩欧美一二区| 国产精品的网站| 五月天精品一区二区三区| 精品午夜久久福利影院| 成人福利在线看| 欧美群妇大交群的观看方式| 欧美精品一区二区三区四区 | 最新日韩av在线| 午夜电影久久久| 国产精品一二三| 91福利在线播放| 久久久久久久久久久久久久久99 | 国产乱子轮精品视频| 91免费国产视频网站| 91麻豆精品国产91久久久| 中文字幕成人网| 日韩中文字幕区一区有砖一区 | 中文字幕 久热精品 视频在线 | 粉嫩一区二区三区在线看| 欧美在线观看你懂的| 久久午夜老司机| 亚洲国产一区二区视频| 国产一区二区三区高清播放| 欧美日韩国产精选| 精品国产乱码久久久久久图片| 欧美日韩视频专区在线播放| 欧美日韩中文字幕一区|