13.類加載及執(zhí)行子系統(tǒng)的案例

Tomcat:正統(tǒng)的類加載器架構(gòu)

image

Tomcat類加載器說明

前面3個類加載和默認(rèn)的一致,CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebappClassLoader則是Tomcat自己定義的類加載器,它們分別加載/common/、/server/、/shared/(在tomcat 6之后已經(jīng)合并到根目錄下的lib目錄下)和/WebApp/WEB-INF/中的Java類庫。其中WebApp類加載器和Jsp類加載器通常會存在多個實例,每一個Web應(yīng)用程序?qū)?yīng)一個WebApp類加載器,每一個JSP文件對應(yīng)一個Jsp類加載器。

  • commonLoader:Tomcat最基本的類加載器,加載路徑中的class可以被Tomcat容器本身以及各個Webapp訪問;

  • catalinaLoader:Tomcat容器私有的類加載器,加載路徑中的class對于Webapp不可見;

  • sharedLoader:各個Webapp共享的類加載器,加載路徑中的class對于所有Webapp可見,但是對于Tomcat容器不可見;

  • WebappClassLoader:各個Webapp私有的類加載器,加載路徑中的class只對當(dāng)前Webapp可見;
    從圖中的委派關(guān)系中可以看出:

  • CommonClassLoader能加載的類都可以被Catalina ClassLoader和SharedClassLoader使用,從而實現(xiàn)了公有類庫的共用,而CatalinaClassLoader和Shared ClassLoader自己能加載的類則與對方相互隔離。

  • WebAppClassLoader可以使用SharedClassLoader加載到的類,但各個WebAppClassLoader實例之間相互隔離。

而JasperLoader的加載范圍僅僅是這個JSP文件所編譯出來的那一個.Class文件,它出現(xiàn)的目的就是為了被丟棄:當(dāng)Web容器檢測到JSP文件被修改時,會替換掉目前的JasperLoader的實例,并通過再建立一個新的Jsp類加載器來實現(xiàn)JSP文件的HotSwap功能。

Tomcat 如果使用默認(rèn)的類加載機制行不行?

我們思考一下:Tomcat是個web容器, 那么它要解決什么問題:

  1. 一個web容器可能需要部署兩個應(yīng)用程序,不同的應(yīng)用程序可能會依賴同一個第三方類庫的不同版本,不能要求同一個類庫在同一個服務(wù)器只有一份,因此要保證每個應(yīng)用程序的類庫都是獨立的,保證相互隔離。
  2. 部署在同一個web容器中相同的類庫相同的版本可以共享。否則,如果服務(wù)器有10個應(yīng)用程序,那么要有10份相同的類庫加載進虛擬機,這是扯淡的。
  3. web容器也有自己依賴的類庫,不能于應(yīng)用程序的類庫混淆?;诎踩紤],應(yīng)該讓容器的類庫和程序的類庫隔離開來。
  4. web容器要支持jsp的修改,我們知道,jsp 文件最終也是要編譯成class文件才能在虛擬機中運行,但程序運行后修改jsp已經(jīng)是司空見慣的事情,否則要你何用? 所以,web容器需要支持 jsp 修改后不用重啟。

Tomcat如果使用默認(rèn)的類加載機制行不行?

答案是不行的。為什么?

第一個問題,如果使用默認(rèn)的類加載器機制,那么是無法加載兩個相同類庫的不同版本的,默認(rèn)的累加器是不管你是什么版本的,只在乎你的全限定類名,并且只有一份。

第二個問題,默認(rèn)的類加載器是能夠?qū)崿F(xiàn)的,因為他的職責(zé)就是保證唯一性。

第三個問題和第一個問題一樣。

我們再看第四個問題,我們想我們要怎么實現(xiàn)jsp文件的HotSwap,jsp 文件其實也就是class文件,那么如果修改了,但類名還是一樣,類加載器會直接取方法區(qū)中已經(jīng)存在的,修改后的jsp是不會重新加載的。那么怎么辦呢?我們可以直接卸載掉這jsp文件的類加載器,所以你應(yīng)該想到了,每個jsp文件對應(yīng)一個唯一的類加載器,當(dāng)一個jsp文件修改了,就直接卸載這個jsp類加載器。重新創(chuàng)建類加載器,重新加載jsp文件。

字節(jié)碼生成技術(shù)與動態(tài)代理的實現(xiàn)

  1. 動態(tài)代理
public class DynamicProxyTest{
    interface IHello{
        void sayHello();
    }
    static class Hello implements IHello{
        @Override
        public void sayHello(){
            System.out.println("Hello class say hello")
        }
    }
    static class DynamicProxy implements InvokecationHandler{
        Object originalObj;
        Object bind(Object originalObj){
            this.originalObj=originalObj;
            return Proxy.newProxyInstance(originalObj.getClass().getClassLoader(),originalObj.getClass().getInterfaces(),this);        
            
        }
        @Override
        public Object invoke(Object proxy,Method method,Object[]args)throw Throwable{
            System.out.println("welcome");
            return method.invoke(originalObj,args);
        }
        public static void main(String []args){
            IHello hello=(IHello) new DynamicProxy().bind(new Hello());
            hello.sayHello();
        }
    }
}
----
welcome
Hello Class say hello
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容