How Tomcat Works學習筆記

 

加載器

         在How Tomcat Works的前七章中的應用中已經在使用簡單的加載器來加載servlet類,這裏將會討論標準web加載器實現,Tomcat爲什麼沒有使用Tomcat默認的加載器呢?因爲如果所有的加載器都是通過jvm默認的加載器來加載的,那麼每個servlet就都能夠操縱classpath下的所有加載類和包,這會帶來安全隱患。一個servlet僅僅允許加載WEB-INF/classes和WEB-INF/lib下的類,在servlet容器中的每一個應用(context)都有它自己的加載器,所有加載器都必須實現org.apache.catalina.Loader接口。

         同時Tomcat需要支持熱加載在應用WEB-INF/classes和WEB-INF/lib下修改的類,這就要求Tomcat加載器有一個線程不斷的檢測類是否有修改(通過檢測每個文件的時間來實現)。所有需要實現熱加載功能的加載器都必須實現org.apache.catalina.loader.Reloader接口。

         這裏會介紹Repository和Resource,repository是加載器搜尋類的地方,resources是一個加載器中DirContext類,指向的是context的基礎路徑。

Java加載器

         每次創建Java類的實例的時候,你必須首先把類加載到內存當中,在jvm用類加載器(loader)加載類,從j2se1.2開始,jvm提供三個加載器bootstray class加載器、extension class加載器和system class加載器,這個三個加載器是一種父子關係,bootstray class 加載器在最上層,system class加載器在最下層。Bootstray 類加載器用來引導jvm,當你運行java.exe的時候開始工作,必須通過本地代碼來實現,因爲jvm它需要調用一些本地函數,同時它也負責加載所有java核心類,像java.lang和java.io包中的類,同時也會去加載核心庫像rt.jar、il8n.jar等等,同時隨着jvm版本和操作系統不同而有所不同;Extension class加載器負責加載擴張目錄下的類,sun公司的jvm中的擴展類在/jdk/jre/lib/ext;System class加載器是默認的類加載器,負責加載在CLASSPATH環境變量中指定目錄下的jar和java類。

         在選擇使用那個加載器的時候,jvm使用了委派模式,當需要加載一個類的時候,system class加載器並不馬上開始工作,它會首先委派它的父加載器extension class加載器,如果父加載器加載失敗它纔會開始工作,同理extension加載類時也會首先委派給它的父加載器bootray加載器,當bootray加載器加載失敗時它纔會工作,當所有的加載器都沒有找到類時就會跑出java.lang.ClassNotFoundException異常。

         之所以使用委派模式是出於安全考慮,避免有人惡意提供一個java.lang.Object,同時java中你可以實現自己的加載器,只需要繼承java.lang.ClassLoader即可。

         基於以下的原因Tomcat需要自己的加載器:

1、  按照確定的規則加載類;

2、  緩存已經加載的類;

3、  重新加載已經修改的類。

加載器接口

         Tomcat的加載器準確的說是web應用加載器,需要保證加載的servlet只能夠使用WEB-INF/classes和WEB-INF/lib庫中的類。所有的加載器必須實現org.apache.catalina.Loader接口。

         Tomcat加載器通常是與Context一起作用的,所以Loader提供了setContainer和getContainer方法,Tomcat需要重新加載已經修改的類,具體加載的工作交給Context去做,但是加載器需要提供一個setReloadable和getReloadable方法,告訴Context是否需要重新加載,這個可以在server.xml文件中進行配置:

         <Context path=”/myApp” docBase=”myApp” debug=”0” reloadable=”true”/>

         加載器接口及其實現類類圖如下:

        

Reloader接口

         爲了支持自動重新加載的功能,每個加載器都需要實現org.apache.catalina.loader.Reloader接口,其接口定義如下:

         package org.apache.catalina.loader;

public interface Reloader {

        public void addRepository(String repository);

        public String[] findRepositories();

        public boolean modified();

}

    最關鍵的是modified方法,它在一個servlet或者servlet的支持類修改以後會返回true,addRepository方法爲加載器添加一個儲藏室。

WebappLoader類

         根據前面的介紹可知,WebappLoader類實現了Loader接口,代表一個web應用加載應用下的所有類,同時它會創建一個org.apache.catalina.loader.WebappClassLoader實例作爲它的類加載器,同時它也實現了org.apahe.catalina.Lifecycle接口,能夠通過它所在的容器(往往是Context)來啓動或停止它,WebappLoader實現Runable接口,用一個線程不斷的調用它的類加載器的modified接口,來檢測是否有類做了修改,在WebappLoader啓動的時候會做下面幾件事情:

1、  創建一個類加載器(class loader);

2、  設置它的儲藏室;

3、  設置他的類路徑;

4、  設置權限;

5、  啓動一個線程進行自動加載。

WebappClassLoader類

         org.apache.catalina.loader.WebappClassLoader類是web應用的類加載器,類加載器被優化和安全的,同時它會緩存預加載的類,當需要用到某類的時候它首先會去從緩存中找,沒有找到時纔會去加載。同時也會緩存查找失敗的類,從安全方面考慮,WebappClassLoader不允許加載一些確定的類,這些類被存儲在一個叫做triggers的數組當中:

         private static final String[] triggers = {

        "javax.servlet.Servlet"                     // Servlet API

};

同時還有一些包下的類也不允許加載:

    private static final String[] packageTriggers = {

        "javax",                                     // Java extensions

        "org.xml.sax",                               // SAX 1 & 2

        "org.w3c.dom",                               // DOM 1 & 2

        "org.apache.xerces",                         // Xerces 1 & 2

        "org.apache.xalan"                           // Xalan

};

加載器類工作的過程如下:

1、 檢測本地緩存(local cache);

2、  如果本地緩存中沒有找到,則在緩存中查找,比如調用java.lang.ClassLoader類的findLoadedClass;

3、  如果在兩個緩存中都沒有找到,這調用系統的加載器,防止覆蓋J2EE中的類;

4、  如果使用SecurityManager,如果不允許,拋出ClassNotFoundException;

5、  如果delegate標誌打開或者類所在包在觸發器中,則調用父加載器,如果沒有父加載器則調用系統默認加載器;

6、  從儲存器中加載類;

7、  如果當前儲存器中類沒有找到,並且delegate標誌未打開,則調用父類加載器,如父加載器沒有找到,則調用系統默認加載器;

8、  如果仍然沒有找到類,則拋出ClassNotFoundException異常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章