honzeland

          記錄點滴。。。

          常用鏈接

          統計

          Famous Websites

          Java

          Linux

          P2P

          最新評論

          Tomcat ClassLoader and load resources

          zz: http://rosonsandy.blogdriver.com/rosonsandy/871539.html

          1 - Tomcat的類載入器的結構
          Tomcat Server在啟動的時候將構造一個ClassLoader樹,以保證模塊的類庫是私有的
          Tomcat Server的ClassLoader結構如下:
                  +-----------------------------+

                  |         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,用來在運行時動態地載入其它類
          系統默認的contextClassLoader是systemClassLoader,所以一般而言java程序在執行時可以使用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類中loadClass方法為缺省實現,用下面的順序查找類:
          1、調用findLoadedClass方法來檢查是否已經被加載。如果沒有則繼續下面的步驟。
          2、如果當前類裝載器有一個指定的委托父裝載器,則用委托父裝載器的loadClass方法加載類,也就是委托給父裝載器加載相應的類。
          3、如果這個類裝載器的委托層級體系沒有一個類裝載器加載該類,則使用類裝載器定位類的特定實現機制,調用findClass方法來查找類。

          4 - 部分原代碼分析
          4.1 - org/apache/catalina/startup/Bootstrap.java
          Bootstrap中定義了三個classloader:commonLoader,catalinaLoader,sharedLoader.三者關系如下:
          //注意三個自己定置的ClassLoader的層次關系:
                      // systemClassLoader (root)
                      //   +--- commonLoader
                      //          +--- catalinaLoader
                      //          +--- sharedLoader

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

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

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

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

          (1) If a system class, use system class loader通過系統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

          根據設置創建并返回StandardClassLoader的實例

          [查看代碼]

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

          類載入器

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

          該類僅包含一個靜態方法,用來為catalinaLoader載入一些類

          [查看代碼]

          Appendix - 參考

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

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

          [2] 深入Java2平臺安全

          zz: http://mail-archives.apache.org/mod_mbox/tomcat-users/200212.mbox/raw/%3c20021204192034.P86616-100000@icarus.apache.org%3e
          try {
              Properties props = new Properties();
              InputStream in = getClass().getResourceAsStream("/conf/db.properties");
              props.load(in);
              ......
              propertie1 = props.getProperty("propertie1");

          The examples already given will find properties files for you just fine whether the file is in a directory structure or inside an archive.  How do you think Java loads classes?  It works out of archives, no? here are some various was to access a properties file ( or any resource, for that matter) in whether the app is deployed as a directory or as a .war file (even inside a .jar file in WEB-INF/lib)....

          1. This will load a file in WEB-INF/classes/conf or any jar file in the classpath with a package of "conf"...
              getClass().getResourceAsStream("/conf/db.properties");
          2. This will load a file relative to the current class.  For instance, if the class is "org.mypackage.MyClass", then the file would be loaded at "org.mypackage.conf.dbproperties".  Note that this is because we didn't prepend "/" to the path.  When that is done, the file is loaded from the root of the current classloader where this loads it relative to the current class...
              getClass().getResourceAsStream("conf/db.properties");
          3. This will find db.properties anywhere in the current classloader as long as it exists in a "conf" package...
              getClass().getClassLoader().getResourceAsStream("conf/db.properties");
          4. This will find the file in a "conf" directory inside the webapp (starting from the root).  This starts looking in the same directory as contains WEB-INF.  When I say "directory", I don't mean "filesystem".  This could be in a .war file as well as in an actual directory on the filesystem...
              getServletContext().getResourceAsStream("/conf/db.properties");
          5. Of course you would probably not want just anyone seeing your db.properties file, so you'd probably want to put in inside WEB-INF of your webapp, so....
              getServletContext().getResourceAsStream("/WEB-INF/conf/db.properties");
          6. If your db.properties exists in another classloader which your app has access to, you can reach it by using:
              Thread.currentThread().getContextClassLoader().getResourceAsStream("conf/db.properties");
          that will act similar to getClass().getClassLoader(), but it can see across all available classloaders where the latter can only see within the classloader that loaded the current class.

          posted on 2008-04-24 15:46 honzeland 閱讀(852) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 怀远县| 墨竹工卡县| 利川市| 蒙城县| 甘肃省| 稷山县| 陈巴尔虎旗| 南昌县| 招远市| 阜宁县| 南投县| 赤水市| 齐齐哈尔市| 盖州市| 巴青县| 赣榆县| 常熟市| 德令哈市| 枣庄市| 元江| 分宜县| 灵武市| 松江区| 郯城县| 米易县| 朝阳区| 曲沃县| 濮阳县| 会东县| 甘孜| 英吉沙县| 元江| 特克斯县| 吉隆县| 洛川县| 洪湖市| 盱眙县| 台南市| 什邡市| 阜宁县| 类乌齐县|