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

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

淺談Tomcat如何打破雙親委托機制

瀏覽:323日期:2023-03-19 16:51:47
目錄
  • JVM的類加載器
  • Tomcat的類加載器
    • findClass
    • loadClass

我們經常會遇到ClassNotFound異常,表明JVM在嘗試加載某類時失敗了。

要解決這個異常,你得知道

  • 什么是類加載
  • JVM如何加載類
  • 為什么會出現ClassNotFound

想想Tomcat又是如何加載和管理Web應用下的Servlet呢?
Tomcat正是通過Context組件來加載管理Web應用的,所以今天我會詳細分析Tomcat的類加載機制。但在這之前,我們有必要預習一下JVM的類加載機制,我會先回答一下一開始拋出來的問題,接著再談談Tomcat的類加載器如何打破Java的雙親委托機制。

JVM的類加載器

Java的類加載,就是把字節碼格式.class文件加載到JVM的方法區,并在JVM堆建立一個java.lang.Class對象實例,封裝Java類相關的數據和方法。

Class對象是什么?
可以理解成業務類的模板,JVM根據該模板創建具體業務類對象實例。

JVM并非在啟動時就把所有 .class 文件都加載一遍,而是程序在運行過程中用到該類才去加載。
JVM類加載由類加載器完成,JDK提供一個抽象類ClassLoader:

public abstract class ClassLoader {

    // 每個類加載器都有個父加載器
    private final ClassLoader parent;
    
    public Class<?> loadClass(String name) {
  
// 查找該類是否被加載過
Class<?> c = findLoadedClass(name);

// 若未被加載過
if( c == null ){
  // 【遞歸】委托給父加載器加載
  if (parent != null) {
      c = parent.loadClass(name);
  } else {
      // 若父加載器為空,查找Bootstrap加載器是否加載過了
      c = findBootstrapClassOrNull(name);
  }
}
// 若父加載器未加載成功,調用自己的findClass去加載
if (c == null) {
    c = findClass(name);
}

return c;
    }
    
    protected Class<?> findClass(String name){
       // 1. 根據傳入的類名name,到在特定目錄下去尋找類文件,把.class文件讀入內存
  ...
  
       // 2. 調用defineClass將字節數組轉成Class對象
       return defineClass(buf, off, len);
    }
    
    // 將字節碼數組解析成一個Class對象,用native方法實現
    protected final Class<?> defineClass(byte[] b, int off, int len){
       ...
    }
}

JVM的類加載器是分層的父子關系,每個類加載器都持有一個parent字段指向父加載器。

  • defineClass 工具方法:調用native方法把Java類的字節碼解析成一個Class對象
  • findClass 就是找到 .class 文件,可能來自文件系統或網絡,找到后把 .class 文件讀到內存得到字節碼數組,然后調用defineClass方法得到Class對象

loadClass 首先檢查這個類是不是已經被加載過了,如果加載過了直接返回,否則交給父加載器去加載。
這是個遞歸調用,即子加載器持有父加載器引用,當一個類加載器需加載一個Java類時,會先委托父加載器去加載,然后父加載器在自己加載路徑中搜索Java類,當父加載器在自己的加載范圍內找不到時,才會交還給子加載器加載,這就是雙親委托機制。

JDK的類加載器工作原理是一樣的,區別只是加載路徑不同,即findClass查找的路徑不同。
雙親委托機制是為保證一個Java類在JVM的唯一性。假如你手滑寫個與JRE核心類同名類,比如Object,雙親委托機制能保證加載的是JRE里的那個Object類,而不是你寫的Object。
因為AppClassLoader在加載你的Object類時,會委托給ExtClassLoader去加載,而ExtClassLoader又會委托給BootstrapClassLoader,BootstrapClassLoader發現自己已經加載過了Object類,會直接返回,不會去加載你的Object類。

類加載器的父子關系不是通過繼承來實現的,比如AppClassLoader并非ExtClassLoader的子類,只是AppClassLoader的parent指向ExtClassLoader對象。
所以若自定義類加載器,不是去繼承AppClassLoader,而是繼承ClassLoader抽象類,再重寫findClass和loadClass即可。
Tomcat就是通過自定義類加載器實現自己的類加載。
若你要打破雙親委托,也就只需重寫loadClass,因為loadClass的默認實現就是雙親委托機制。

Tomcat的類加載器

Tomcat的自定義類加載器WebAppClassLoader打破了雙親委托機制:
首先自己嘗試去加載某個類,如果找不到再委托給父類加載器,目的是優先加載Web應用自己定義的類。
只需重寫ClassLoader的兩個方法:

findClass

public Class<?> findClass(String name) throws ClassNotFoundException {
    ...
    
    Class<?> clazz = null;
    try {
    //1. 先在Web應用目錄下查找類 
    clazz = findClassInternal(name);
    }  catch (RuntimeException e) {
   throw e;
       }
    
    if (clazz == null) {
    try {
    //2. 如果在本地目錄沒有找到,交給父加載器去查找
    clazz = super.findClass(name);
    }  catch (RuntimeException e) {
   throw e;
       }
    
    //3. 如果父類也沒找到,拋出ClassNotFoundException
    if (clazz == null) {
throw new ClassNotFoundException(name);
     }

    return clazz;
}

工作流程

  • 先在Web應用本地目錄下查找要加載的類
  • 若未找到,交給父加載器查找,即AppClassLoader
  • 若父加載器也沒找到這個類,拋ClassNotFound

loadClass

public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {

    synchronized (getClassLoadingLock(name)) {
 
Class<?> clazz = null;

//1. 先在本地cache查找該類是否已經加載過
clazz = findLoadedClass0(name);
if (clazz != null) {
    if (resolve)
resolveClass(clazz);
    return clazz;
}

//2. 從系統類加載器的cache中查找是否加載過
clazz = findLoadedClass(name);
if (clazz != null) {
    if (resolve)
resolveClass(clazz);
    return clazz;
}

// 3. 嘗試用ExtClassLoader類加載器類加載,為什么?
ClassLoader javaseLoader = getJavaseClassLoader();
try {
    clazz = javaseLoader.loadClass(name);
    if (clazz != null) {
if (resolve)
    resolveClass(clazz);
return clazz;
    }
} catch (ClassNotFoundException e) {
    // Ignore
}

// 4. 嘗試在本地目錄搜索class并加載
try {
    clazz = findClass(name);
    if (clazz != null) {
if (resolve)
    resolveClass(clazz);
return clazz;
    }
} catch (ClassNotFoundException e) {
    // Ignore
}

// 5. 嘗試用系統類加載器(也就是AppClassLoader)來加載
    try {
clazz = Class.forName(name, false, parent);
if (clazz != null) {
    if (resolve)
resolveClass(clazz);
    return clazz;
}
    } catch (ClassNotFoundException e) {
// Ignore
    }
       }
    
    //6. 上述過程都加載失敗,拋出異常
    throw new ClassNotFoundException(name);
}

工作流程

  • 先在本地Cache查找該類是否已加載過
  • 即Tomcat的類加載器是否已經加載過這個類。
  • 若Tomcat類加載器尚未加載過該類,再看看系統類加載器是否加載過
  • 若都沒有,就讓ExtClassLoader加載,為防止Web應用自己的類覆蓋JRE的核心類
  • 因為Tomcat需打破雙親委托,假如Web應用里自定義了一個叫Object的類,若先加載該Object類,就會覆蓋JRE的Object類,所以Tomcat類加載器優先嘗試用ExtClassLoader去加載,因為ExtClassLoader會委托給BootstrapClassLoader去加載,BootstrapClassLoader發現自己已經加載了Object類,直接返回給Tomcat的類加載器,這樣Tomcat的類加載器就不會去加載Web應用下的Object類了,避免覆蓋JRE核心類。
  • 若ExtClassLoader加載失敗,即JRE無此類,則在本地Web應用目錄下查找并加載
  • 若本地目錄下無此類,說明不是Web應用自己定義的類,那么由系統類加載器去加載。這里請你注意,Web應用是通過Class.forName調用交給系統類加載器的,因為Class.forName的默認加載器就是系統類加載器。
  • 若上述加載過程都失敗,拋ClassNotFound

可見 Tomcat 類加載器打破了雙親委托,沒有一上來就直接委托給父加載器,而是先在本地目錄下加載。
但為避免本地目錄類覆蓋JRE核心類,會先嘗試用ExtClassLoader加載。
那為何不先用AppClassLoader加載?
若這樣,就又變成雙親委托,這就是Tomcat類加載器的奧妙。

到此這篇關于淺談Tomcat如何打破雙親委托機制的文章就介紹到這了,更多相關Tomcat 雙親委托機制內容請搜索以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持!

標簽: Tomcat
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
在线手机中文字幕| 亚洲精品2区| 欧美日韩在线播放视频| 视频一区视频二区中文字幕| 日韩福利一区| 日本成人手机在线| 人人精品人人爱| 久久久久久自在自线| 91精品日本| 亚洲人妖在线| 热久久久久久| 国产成人黄色| 精品国产乱码久久久久久樱花| 日本电影久久久| 国产精品亚洲欧美一级在线| 国产精品毛片久久久| 国产精品白丝av嫩草影院| 免费久久99精品国产| 99国产精品久久久久久久| 一区久久精品| 狠狠久久婷婷| 91午夜精品| 国产欧美日韩免费观看| 美女毛片一区二区三区四区最新中文字幕亚洲 | 亚洲精一区二区三区| 久久99偷拍| 日本欧美不卡| 免费在线观看日韩欧美| 精品国产欧美日韩| 高清久久一区| 不卡一区2区| 亚洲视频国产| 中文一区一区三区高中清不卡免费| 最新日韩av| 国产精品视频一区二区三区四蜜臂| 日韩精品欧美| 在线观看视频免费一区二区三区| 国产精品麻豆成人av电影艾秋| 久久精品国产亚洲一区二区三区| 日韩视频一区| 超碰99在线| 亚洲精品看片| 中国女人久久久| 日韩中文字幕无砖| 精品一区二区三区中文字幕在线| 欧美天堂亚洲电影院在线观看| 视频一区中文字幕精品| 欧美韩日一区| 亚洲精品第一| 国产精品日本欧美一区二区三区| 99精品国产一区二区三区| 中文字幕一区二区三区四区久久| 在线观看精品| 久久99久久久精品欧美| 免费视频最近日韩| 国产精品嫩草99av在线| 麻豆视频在线观看免费网站黄 | 影音先锋国产精品| 欧美天堂视频| 日本中文字幕一区二区| 亚洲午夜久久久久久尤物| 精品香蕉视频| 日韩国产欧美视频| 综合激情在线| 欧美精品国产| 免费在线亚洲欧美| 日韩精品久久久久久| 蜜臀av在线播放一区二区三区| 91久久久久| 日韩在线卡一卡二| 91精品国产成人观看| 波多野结衣久久精品| 精品国产91| 91一区二区| 日韩精品1区| 国产精选在线| 亚洲国产综合在线看不卡| 美女精品在线观看| 亚洲天堂免费| 国产伦精品一区二区三区在线播放| 日韩不卡一二三区| 日韩欧美美女在线观看| 国产午夜一区| 成人国产综合| 亚洲一区国产一区| 国产欧美日韩精品高清二区综合区 | 九一国产精品| 日韩一级精品| 日韩三级精品| 国产专区精品| 日韩中文字幕高清在线观看| 亚洲香蕉网站| 91在线成人| 性感美女一区二区在线观看| 中文字幕中文字幕精品| 日本视频中文字幕一区二区三区| 国产精品99久久免费| 精品国产日韩欧美精品国产欧美日韩一区二区三区 | 久久精品av麻豆的观看方式| 国产精品久久久久久久久久久久久久久 | 亚洲综合不卡| 国产日韩中文在线中文字幕| 精品中文字幕一区二区三区四区| 欧美亚洲在线日韩| 一区二区不卡| 国产精品13p| 欧美一区91| 日韩视频一区二区三区在线播放免费观看| 久久精品凹凸全集| 视频在线观看91| 久久av免费看| 日本精品另类| 在线亚洲国产精品网站| 国产激情久久| 视频在线观看一区二区三区| 久久中文字幕av一区二区不卡| 国产欧美自拍| 免费欧美在线视频| 国产精久久久| 国产欧美一区二区三区米奇| 婷婷成人av| 欧美日韩视频一区二区三区| 成人影视亚洲图片在线| 国产高清亚洲| 国产日韩在线观看视频| 色综合视频一区二区三区日韩 | 婷婷精品进入| 91精品久久久久久久久久不卡| 日韩中文影院| 欧美一区二区三区激情视频| 久久影院午夜精品| 免费在线视频一区| 三级在线观看一区二区| 亚洲欧洲美洲国产香蕉| 最新国产拍偷乱拍精品| 少妇久久久久| 肉色欧美久久久久久久免费看| 97精品97| 影视先锋久久| 亚洲成人一区在线观看| 精品捆绑调教一区二区三区| 亚洲成人国产| 蜜桃一区二区三区在线观看| 蜜臀精品久久久久久蜜臀| 一区二区亚洲视频| 奇米狠狠一区二区三区| 久久精品日韩欧美| 99视频精品全国免费| 亚洲专区在线| 国产精品美女午夜爽爽| 日本韩国欧美超级黄在线观看| 1024精品一区二区三区| 亚洲欧洲日韩精品在线| 久久69成人| 日韩av一级| 婷婷综合国产| 国产一区二区三区四区大秀| 国产伊人精品| 国产亚洲一区二区三区不卡| 久久狠狠久久| se01亚洲视频| 久久午夜精品| 麻豆成全视频免费观看在线看| 国产精品伦理久久久久久| 久久亚洲欧洲| 久久精品一本| 亚洲午夜免费| 久久久噜噜噜| 欧美aaaaaa午夜精品| 日韩久久精品| 日韩专区视频网站| 女同性一区二区三区人了人一| 国产欧美综合一区二区三区| 亚洲一区二区三区高清不卡| 日本久久综合| 久久伊人久久| 日韩国产高清在线| 亚洲精品少妇| 亚洲一级在线| 久久精品动漫| 欧美午夜精品一区二区三区电影| 国产成人精品福利| 日本午夜精品一区二区三区电影| 蜜桃视频免费观看一区| 国产一区日韩一区| 欧美视频一区| 激情综合自拍| 久久婷婷av| 国产精品一区二区av日韩在线| 久久夜色精品| 国内精品99| 私拍精品福利视频在线一区| 不卡专区在线| 99精品美女| 最新国产拍偷乱拍精品| 欧美一区二区性| 精品免费av在线| 午夜国产欧美理论在线播放| 日韩在线短视频| 亚州av乱码久久精品蜜桃|