海闊天空

          I'm on my way!
          隨筆 - 17, 文章 - 69, 評論 - 21, 引用 - 0
          數(shù)據(jù)加載中……

          啟動期間的加載類的順序和過程

          Tomcat啟動時classloader加載順序
          Tomcat的class加載的優(yōu)先順序一覽  
          1.最先是$JAVA_HOME/jre/lib/ext/下的jar文件。  
          2.環(huán)境變量CLASSPATH中的jar和class文件。  
          3.$CATALINA_HOME/common/classes下的class文件。  
          4.$CATALINA_HOME/commons/endorsed下的jar文件。  
          5.$CATALINA_HOME/commons/i18n下的jar文件。  
          6.$CATALINA_HOME/common/lib   下的jar文件。  
          (JDBC驅(qū)動之類的jar文件可以放在這里,這樣就可以避免在server.xml配置好數(shù)據(jù)源卻出現(xiàn)找不到JDBC   Driver的情況。)  
          7.$CATALINA_HOME/server/classes下的class文件。  
          8.$CATALINA_HOME/server/lib/下的jar文件。  
          9.$CATALINA_BASE/shared/classes   下的class文件。  
          10.$CATALINA_BASE/shared/lib下的jar文件。  
          11.各自具體的webapp   /WEB-INF/classes下的class文件。  
          12.各自具體的webapp   /WEB-INF/lib下的jar文件。  
          class的搜尋順序如下:  
          -------------  
          Bootstrap   classes   of   your   JVM    
          System   class   loader   classses   (described   above)    
          /WEB-INF/classes   of   your   web   application    
          /WEB-INF/lib/*.jar   of   your   web   application    
          $CATALINA_HOME/common/classes    
          $CATALINA_HOME/common/endorsed/*.jar    
          $CATALINA_HOME/common/i18n/*.jar    
          $CATALINA_HOME/common/lib/*.jar    
          $CATALINA_BASE/shared/classes    
          $CATALINA_BASE/shared/lib/*.jar    
          --------------  
          因此放在不同webapp里的class文件,會被classloader加載成不同的實例。  
          例如假設(shè)下面兩個不同內(nèi)容的class。分別放在不同的webapp的class目錄下。  
          package   com.lizongbo;  
          public   class   TestClass   {  
                private   String   NAME="lizongbo";  
          }  
          package   com.lizongbo;  
          public   class   TestClass   {  
                private   String   NAME="li_zongbo";  
          }  
          在不同的webapp得到的com.lizongbo.NAME結(jié)果是不同的,且互不影響。  
          但是注意,以下包名開頭的class例外:  
          javax.*    
          org.xml.sax.*    
          org.w3c.dom.*    
          org.apache.xerces.*    
          org.apache.xalan.*    
          ps,注意.在各個jar中的\META-INF\MAINFEST.MF文件里Class-Path鍵值對,也會提供jar的加載優(yōu)先順序。  
          例如某jar的MAINFEST.MF內(nèi)容如下:  
          Manifest-Version:   1.0  
          Created-By:   lizongbo  
          Class-Path:   commons-beanutils.jar  
          Class-Path:   commons-collections.jar  
          Class-Path:   commons-dbcp.jar  
          Class-Path:   commons-digester.jar  
          Class-Path:   commons-logging.jar  
          Class-Path:   commons-pool.jar  
          Class-Path:   commons-services.jar  
          Class-Path:   commons-validator.jar  
          Class-Path:   jakarta-oro.jar  
          Main-Class:   com.lizongbo.MyTestClass  
          那么在加載這個jar的時候,會先在此jar所在目錄下依次先加載commons-beanutils.jar,commons-collections.jar。。。等jar文件。  
          在不同的地方放置jar和class可能會產(chǎn)生意想不到的后果,,尤其是不同版本的jar文件,因此在實際應(yīng)用部署web應(yīng)用時候要特別留心.  
          例如   使用javamail常見的一個出錯信息:  
          javax.mail.NoSuchProviderException:   No   provider   for   smtp  
          其真實原因就很可能如下:  
          在不同的加載jar的目錄下放置了不同版本的mail.jar,比如一個是javamail1.3.1的mail.jar  
          在D:\jakarta-tomcat-5.5.8\common\lib下,而另外一個是javamail1.3.2的mail.jar在  
          D:\jakarta-tomcat-5.5.8\webapps\lizongbo\WEB-INF/lib下,  
          那么lizongbo這個webapp中使用到j(luò)avamail進行郵件發(fā)送的時候,便會出現(xiàn)No   provider   for   smtp的錯誤。  
          *******************************************************************
          ClassLoader in Tomcat
          ************************************
          1 - Tomcat 的類載入器的結(jié)構(gòu)


          Tomcat Server 在啟動的時候?qū)?gòu)造一個ClassLoader樹,以保證模塊的類庫是私有的
          Tomcat Server的ClassLoader結(jié)構(gòu)如下:


                  +-----------------------------+

                  |         Bootstrap           |

                  |             |               |

                  |          System             |

                  |             |               |

                  |          Common             |

                  |         /      \            |

                  |     Catalina Shared        |

                  |               /    \        |

                   |          WebApp1 WebApp2   |

                  +-----------------------------+


          其中:
          - Bootstrap - 載入JVM自帶的類和$JAVA_HOME/jre/lib/ext/*.jar
          - System - 載入$CLASSPATH/*.class
          - Common - 載入$CATALINA_HOME/common/...,它們對TOMCAT和所有的WEB APP都可見
          - Catalina - 載入$CATALINA_HOME/server/...,它們僅對TOMCAT可見,對所有的WEB APP都不可見
          - Shared - 載入$CATALINA_HOME/shared/...,它們僅對所有WEB APP可見,對TOMCAT不可見(也不必見)
          - WebApp - 載入ContextBase?/WEB-INF/...,它們僅對該WEB APP可見



          2 - ClassLoader 的工作原理


          每個運行中的線程都有一個成員contextClassLoader,用來在運行時動態(tài)地載入其它類
          系統(tǒng)默認的contextClassLoader是systemClassLoader,所以一般而言java程序在執(zhí)行時可以使用JVM自帶的類、$JAVA_HOME/jre/lib/ext/中的類和$CLASSPATH/中的類
          可以使用 Thread.currentThread().setContextClassLoader(...); 更改當前線程的contextClassLoader,來改變其載入類的行為


          ClassLoader 被組織成樹形,一般的工作原理是:
          1) 線程需要用到某個類,于是contextClassLoader被請求來載入該類
          2) contextClassLoader請求它的父ClassLoader來完成該載入請求
          3) 如果父ClassLoader無法載入類,則contextClassLoader試圖自己來載入


          注意 :WebApp?ClassLoader的工作原理和上述有少許不同:
          它先試圖自己載入類(在ContextBase?/WEB-INF/...中載入類),如果無法載入,再請求父ClassLoader完成


          由此可得:
          - 對于WEB APP線程,它的contextClassLoader是WebApp?ClassLoader
          - 對于Tomcat Server線程,它的contextClassLoader是CatalinaClassLoader



          3 類的查找

          ClassLoader類中l(wèi)oadClass方法為缺省實現(xiàn),用下面的順序查找類:

          1、調(diào)用findLoadedClass方法來檢查是否已經(jīng)被加載。如果沒有則繼續(xù)下面的步驟。

          2、如果當前類裝載器有一個指定的委托父裝載器,則用委托父裝載器的loadClass方法加載類,也就是委托給父裝載器加載相應(yīng)的類。

          3、如果這個類裝載器的委托層級體系沒有一個類裝載器加載該類,則使用類裝載器定位類的特定實現(xiàn)機制,調(diào)用findClass方法來查找類。



          4 - 部分原代碼分析


          4.1 - org/apache/catalina/startup/Bootstrap.java

          Bootstrap中定義了三個classloader:commonLoader,catalinaLoader,sharedLoader.三者關(guān)系如下:


          // 注意三個自己定置的ClassLoader的層次關(guān)系:

                      // systemClassLoader (root)

                        //   +--- commonLoader

                      //          +--- catalinaLoader

                      //          +--- sharedLoader


          Tomcat Server 線程的起點
          構(gòu)造ClassLoader樹,通過Thread.currentThread().setContextClassLoader(catalinaLoader)設(shè)置當前的classloader為catalinaLoader。
          載入若干類,然后轉(zhuǎn)入org.apache.catalina.startup.Catalina類中



          4.2 org.apache.catalina.loader.StandardClassLoader.java

          通過看loadClass這個方法來看tomcat是如何加載類的,順序如下:

          (0) Check our previously loaded class cache查找已經(jīng)裝載的class
                  clazz = findLoadedClass(name);

          (1) If a system class, use system class loader通過系統(tǒng)classloader來裝載class

                  ClassLoader loader = system;
                      clazz = loader.loadClass(name);

          (2) Delegate to our parent if requested如果有代理則使用父類classloader

                      ClassLoader loader = parent;
                      if (loader == null)
                          loader = system;
                      clazz = loader.loadClass(name);

          (3) Search local repositories 查找本地類池,比如$CATALINA_HOME/server

                     clazz = findClass(name);

          (4) Delegate to parent unconditionally 默認使用代理裝載器



          [ 查看代碼]


          4.3 - org/apache/catalina/startup/ClassLoaderFactory.java


          根據(jù)設(shè)置創(chuàng)建并返回StandardClassLoader的實例


          [ 查看代碼]


          4.4 - org/apache/catalina/loader/StandardClassLoader.java


          類載入器


          4.5 - org/apache/catalina/startup/SecurityClassLoad.java


          該類僅包含一個靜態(tài)方法,用來為catalinaLoader載入一些類


          [ 查看代碼]


          Appendix - 參考


          [1] http://jakarta.apache.org/tomcat/ 中的Tomcat 4.1.x文檔Class Loader HOW-TO


          在一個 JVM 中可能存在多個 ClassLoader ,每個 ClassLoader 擁有自己的 NameSpace 。一個 ClassLoader 只能擁有一個 class 對象類型的實例,但是不同的 ClassLoader 可能擁有相同的 class 對象實例,這時可能產(chǎn)生致命的問題。如 ClassLoaderA ,裝載了類 A 的類型實例 A1 ,而 ClassLoaderB ,也裝載了類 A 的對象實例 A2 。邏輯上講 A1=A2 ,但是由于 A1 和 A2 來自于不同的 ClassLoader ,它們實際上是完全不同的,如果 A 中定義了一個靜態(tài)變量 c ,則 c 在不同的 ClassLoader 中的值是不同的。

          posted on 2009-07-01 18:44 石頭@ 閱讀(1011) 評論(0)  編輯  收藏 所屬分類: tomcat_core


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 融水| 衡阳县| 镇远县| 横峰县| 济源市| 莱州市| 平凉市| 兴和县| 舒城县| 安岳县| 永平县| 泾阳县| 广元市| 南投县| 民乐县| 盐池县| 德保县| 石门县| 威远县| 郑州市| 台州市| 嘉义市| 吴忠市| 新野县| 仙居县| 八宿县| 东平县| 环江| 从化市| 和林格尔县| 石柱| 新津县| 离岛区| 桐柏县| 昭通市| 鲜城| 静宁县| 肃南| 台东县| 寿阳县| 天津市|