Tomcat:正統(tǒng)的類加載器架構(gòu)
Tomcat類加載器說明
前面3個類加載和默認的一致链嘀,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只對當前Webapp可見罕拂;
從圖中的委派關(guān)系中可以看出:CommonClassLoader能加載的類都可以被Catalina ClassLoader和SharedClassLoader使用揍异,從而實現(xiàn)了公有類庫的共用全陨,而CatalinaClassLoader和Shared ClassLoader自己能加載的類則與對方相互隔離。
WebAppClassLoader可以使用SharedClassLoader加載到的類衷掷,但各個WebAppClassLoader實例之間相互隔離辱姨。
而JasperLoader的加載范圍僅僅是這個JSP文件所編譯出來的那一個.Class文件,它出現(xiàn)的目的就是為了被丟棄:當Web容器檢測到JSP文件被修改時戚嗅,會替換掉目前的JasperLoader的實例雨涛,并通過再建立一個新的Jsp類加載器來實現(xiàn)JSP文件的HotSwap功能。
Tomcat 如果使用默認的類加載機制行不行懦胞?
我們思考一下:Tomcat是個web容器替久, 那么它要解決什么問題:
- 一個web容器可能需要部署兩個應(yīng)用程序,不同的應(yīng)用程序可能會依賴同一個第三方類庫的不同版本躏尉,不能要求同一個類庫在同一個服務(wù)器只有一份蚯根,因此要保證每個應(yīng)用程序的類庫都是獨立的,保證相互隔離胀糜。
- 部署在同一個web容器中相同的類庫相同的版本可以共享颅拦。否則,如果服務(wù)器有10個應(yīng)用程序教藻,那么要有10份相同的類庫加載進虛擬機距帅,這是扯淡的。
- web容器也有自己依賴的類庫括堤,不能于應(yīng)用程序的類庫混淆碌秸。基于安全考慮悄窃,應(yīng)該讓容器的類庫和程序的類庫隔離開來讥电。
- web容器要支持jsp的修改,我們知道轧抗,jsp 文件最終也是要編譯成class文件才能在虛擬機中運行允趟,但程序運行后修改jsp已經(jīng)是司空見慣的事情,否則要你何用鸦致? 所以,web容器需要支持 jsp 修改后不用重啟涣楷。
Tomcat如果使用默認的類加載機制行不行分唾?
答案是不行的。為什么狮斗?
第一個問題绽乔,如果使用默認的類加載器機制,那么是無法加載兩個相同類庫的不同版本的碳褒,默認的累加器是不管你是什么版本的折砸,只在乎你的全限定類名看疗,并且只有一份。
第二個問題睦授,默認的類加載器是能夠?qū)崿F(xiàn)的两芳,因為他的職責就是保證唯一性。
第三個問題和第一個問題一樣去枷。
我們再看第四個問題怖辆,我們想我們要怎么實現(xiàn)jsp文件的HotSwap,jsp 文件其實也就是class文件删顶,那么如果修改了竖螃,但類名還是一樣,類加載器會直接取方法區(qū)中已經(jīng)存在的逗余,修改后的jsp是不會重新加載的特咆。那么怎么辦呢?我們可以直接卸載掉這jsp文件的類加載器录粱,所以你應(yīng)該想到了腻格,每個jsp文件對應(yīng)一個唯一的類加載器,當一個jsp文件修改了关摇,就直接卸載這個jsp類加載器荒叶。重新創(chuàng)建類加載器,重新加載jsp文件输虱。
字節(jié)碼生成技術(shù)與動態(tài)代理的實現(xiàn)
- 動態(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