tomcat類加載器爲何要破壞雙親委派機制?

1、tomcat是個web容器,要解決如下問題html

1. 一個web容器可能要部署兩個或者多個應用程序,不一樣的應用程序,可能會依賴同一個第三方類庫的不一樣版本,所以要保證每個應用程序的類庫都是獨立、相互隔離的。web

2. 部署在同一個web容器中的相同類庫的相同版本能夠共享,不然,會有重複的類庫被加載進JVM緩存

3. web容器也有本身的類庫,不能和應用程序的類庫混淆,須要相互隔離tomcat

4. web容器支持jsp文件修改後不用重啓,jsp文件也是要編譯成.class文件的,支持HotSwap功能服務器

 

2、tomcat使用Java默認類加載器的問題數據結構

1. 默認的類加載器沒法加載兩個相同類庫的不一樣版本,它只在意類的全限定類名,而且只有一份,因此沒法解決上面1和3,相互隔離的問題架構

2. 修改jsp文件後,由於類名同樣,默認的類加載器不會從新加載,而是使用方法區中已經存在的類;因此須要每一個jsp對應一個惟一的類加載器,當修改jsp的時候,直接卸載惟一的類加載器,而後從新建立類加載器,並加載jsp文件app

 

3、tomcat的類加載機制webapp

1. 架構圖jsp

2. tomcat本身定義的類加載器:

CommonClassLoader:tomcat最基本的類加載器,加載路徑中的class能夠被tomcat和各個webapp訪問

CatalinaClassLoader:tomcat私有的類加載器,webapp不能訪問其加載路徑下的class,即對webapp不可見

SharedClassLoader:各個webapp共享的類加載器,對tomcat不可見

WebappClassLoader:webapp私有的類加載器,只對當前webapp可見

JspClassLoader

3. 每個web應用程序對應一個WebappClassLoader,每個jsp文件對應一個JspClassLoader,因此這兩個類加載器有多個實例

4. 工做原理:

a. CommonClassLoader能加載的類均可以被Catalina ClassLoader和SharedClassLoader使用,從而實現了公有類庫的共用

b. CatalinaClassLoader和Shared ClassLoader本身能加載的類則與對方相互隔離

c. WebAppClassLoader可使用SharedClassLoader加載到的類,但各個WebAppClassLoader實例之間相互隔離,多個WebAppClassLoader是同級關係

d. 而JasperLoader的加載範圍僅僅是這個JSP文件所編譯出來的那一個.Class文件,它出現的目的就是爲了被丟棄:當Web容器檢測到JSP文件被修改時,會替換掉目前的JasperLoader的實例,並經過再創建一個新的Jsp類加載器來實現JSP文件的HotSwap功能

5. tomcat目錄結構,與上面的類加載器對應

/common/*

/server/*

/shared/*

/WEB-INF/*

6. 默認狀況下,conf目錄下的catalina.properties文件,沒有指定server.loader以及shared.loader,因此tomcat沒有創建CatalinaClassLoader和SharedClassLoader的實例,這兩個都會使用CommonClassLoader來代替。Tomcat6以後,把common、shared、server目錄合成了一個lib目錄。因此在咱們的服務器裏看不到common、shared、server目錄。

 

 

4、tomcat類加載器和雙親委派模型的關係

1. tomcat爲了實現隔離性和熱替換,沒有使用默認的類加載器,而是本身實現了類加載器:

每一個webappClassLoader加載本身目錄下的class文件

每一個jasper類加載器加載一個jsp文件

2. 雙親委派模型的標準是:每一個類加載器要加載類的時候,先傳給父類加載器加載,父類加載器加載不了的時候,才由本身加載

3. webappClassLoader和jasperClassLoader沒有傳給父類加載器去加載,仍是傳給了父類加載器而父類加載器加載不了?先本身加載

4. 從WebappClassLoader.loadClass源碼上看,確實沒有傳給父類加載器去加載,確實破壞了雙親委派模型,對於一些未加載的非基礎類(非Object,String等),各個web應用本身的類加載器(WebAppClassLoader)會優先加載,加載不到時再交給commonClassLoader走雙親委託

hasExternalRepositories && searchExternalFirst 默認爲false

5. 爲何要破壞?不破壞行不行?每一個webapp有本身的目錄和類庫,好比一個webapp使用類庫A1.0版本,一個webapp使用類庫A2.0版本,父類加載器加載類庫A1.0版本,若是使用雙親委派,會由commonClassLoader去加載類庫A1.0版本,這樣第二個webapp會有問題

6. 能夠經過在Context.xml文件中加上<Loader delegate = "true">開啓正統的「雙親委派」加載機制

public Class<?> findClass(String name) throws ClassNotFoundException { // 其餘代碼略去..... // Ask our superclass to locate this class, if possible // (throws ClassNotFoundException if it is not found)
        Class<?> clazz = null; try { if (log.isTraceEnabled()) log.trace("      findClassInternal(" + name + ")"); // (1)默認爲false
            if (hasExternalRepositories && searchExternalFirst) { try { clazz = super.findClass(name); } catch(ClassNotFoundException cnfe) { // Ignore - will search internal repositories next
                } catch(AccessControlException ace) { log.warn("WebappClassLoaderBase.findClassInternal(" + name + ") security exception: " + ace.getMessage(), ace); throw new ClassNotFoundException(name, ace); } catch (RuntimeException e) { if (log.isTraceEnabled()) log.trace("      -->RuntimeException Rethrown", e); throw e; } } // (2)
            if ((clazz == null)) { try { clazz = findClassInternal(name); } catch(ClassNotFoundException cnfe) { if (!hasExternalRepositories || searchExternalFirst) { throw cnfe; } } catch(AccessControlException ace) { log.warn("WebappClassLoaderBase.findClassInternal(" + name + ") security exception: " + ace.getMessage(), ace); throw new ClassNotFoundException(name, ace); } catch (RuntimeException e) { if (log.isTraceEnabled()) log.trace("      -->RuntimeException Rethrown", e); throw e; } } //其餘代碼略去........
        return (clazz); }

 

 加載過程:

  1. 先在本地緩存中查找是否已經加載過該類(對於一些已經加載了的類,會被緩存在resourceEntries這個數據結構中),若是已經加載即返回,不然 繼續下一步。
  2. 讓系統類加載器(AppClassLoader)嘗試加載該類,主要是爲了防止一些基礎類會被web中的類覆蓋,若是加載到即返回,返回繼續。
  3. 前兩步均沒加載到目標類,那麼web應用的類加載器將自行加載,若是加載到則返回,不然繼續下一步。
  4. 最後仍是加載不到的話,則委託父類加載器(Common ClassLoader)去加載。

 

 

5、其餘破壞了雙親委派模型的技術

1. OSGI是基於Java語言的動態模塊化規範,類加載器之間是網狀結構,更加靈活,可是也更復雜

2. JNDI服務,使用線程上線文類加載器,父類加載器去使用子類加載器

 

 

 

 

參考文檔:

http://www.javashuo.com/article/p-nqgssvfe-d.html

http://www.javashuo.com/article/p-hdpezkrq-hx.html

http://www.javashuo.com/article/p-blkkoeru-dm.html

相關文章
相關標籤/搜索