深入瞭解WebLogic的類裝載機制詳解
如果大家對一般類的裝載器熟悉的話,就知道在java中類的裝載採用“代理機制”,即子裝載器如果需要裝載一個類檔案,首先會將此任務提交給父裝載器,如果父裝載器找不到此類檔案,才有子裝載器來裝載類檔案,如果子裝載器也找不到,那麼就會報告ClassNotFoundException異常。
1.Weblogic允許定製的類裝載器,同時也有一個預設的類裝載器。其預設的裝載器的結構分層如下:
當部署一個應用的時候,weblogic server會自動建立一個具有層次結構的類裝載器。在圖中,a.Application Classloader負責裝載應用中的所有的EJB JAR檔案;
b.Web Application Classloader負責裝載所有的Web application 中的WAR 檔案(所有得jsp檔案除外);
c.Jsp Classloader 負責裝載Web application 中的所有的jsp 檔案;
這樣的分層結構有一個好處,就是在Jsp,Servlet中可以直接訪問EJB的介面。這種上層裝載EJB,下層裝載servlet等,最下面裝載jsp檔案的結構,使得經常變動的jsp,servlet等可以被重新裝載而不會涉及到EJB層。
在這種預設的類裝載器結構下,有一點需要提出的是:
a. 我們的應用必須打包成一個EAR檔案,才會允許我們應用中的jsp和servlet檔案直接訪問ejb;如果將WAR與JAR檔案分別打包。Weblogic server會為他們分別生成一個類裝載器,作為兄弟節點,這時如果需要在jsp或者servlet中使用ejb,就必須將EJB的Home介面與remote介面打包到WAR中才可以。後面這種情況,適合用在將EJB的客戶端和EJB部署在不同的JVM中;
b.web application classloader中,不會裝載jsp檔案,jsp檔案由web application classloader的子裝載器Jsp classloader負責裝載,因為jsp檔案經常的變動,通過為jsp設立一個單獨的classloader可以避免對jsp的裝載影響到其他的java class或者ejb;
預設裝載器的優點:
a. 呼叫ejb的時候可以採用call-by-referrence的方式;
b. 允許web module獨立的裝載,不影響其它的web module;
通過在將整個應用打包成一個EAR檔案,可以方便的不用再web module中包含EJB的home和remote介面,就可以方便的通過call-by-referrence來呼叫ejb;
2. 定製classloader
如果覺得預設的類裝載器不能滿足需要,weblogic server支援定製的類裝載器。在weblogic的文件中指出,自定義的classloader多用於開發者使用,當應用釋出之後,不推薦使用。自定義的類裝載器通過xml檔案來描述。描述檔案放在weblogic-application.xml中。Weblogic官方提供的DTD描述檔案如下:
<classloader-structure>
<module-ref>
<module-uri>ejba.jar</module-uri>
</module-ref>
<module-ref>
<module-uri>webc.war</module-uri>
</module-ref>
<classloader-structure>
<module-ref>
<module-uri>weba.war</module-uri>
</module-ref>
</classloader-structure>
<classloader-structure>
<module-ref>
<module-uri>ejbc.jar</module-uri>
</module-ref>
<module-ref>
<module-uri>webb.war</module-uri>
</module-ref>
<classloader-structure>
<module-ref>
<module-uri>webd.war</module-uri>
</module-ref>
</classloader-structure>
<classloader-structure>
<module-ref>
<module-uri>ejbb.jar</module-uri>
</module-ref>
</classloader-structure>
</classloader-structure>
</classloader-structure>
通過我們給出的配置檔案,我們自定義的classloader的層次結構如下圖:
在J2EE的規範中明確的指出,J2EE應用不應該依賴於任一個給定的類裝載器。所以,我們自定義的類裝載器,在開發過程中還是可以使用的,但一定不要應用於釋出後的應用中。
自定義的類裝載器有如下得限制:
a.不能夠裝載servlet;
b.巢狀的深度最大為3,也就是說,最多隻能夠巢狀三層;
c.自定義裝載器的module型別僅限於 Web和 EJB這兩種;
d.Jsp Classloader不受此自定義類裝載器的影響,它永遠都是web module的子類裝載器;
相同的類可能導致部署異常;
在自定義的類裝載器中,如果要使用EJB,就必須將EJB的home和remote介面打包到相應的web module中去;
3.Ejb的單獨載入
有時候我們可能需要單獨載入某個EJB,這個時候我們可以通過以下兩種方法來實現:
第一:將應用需要的jar檔案放在APP-INF/lib中,或者將類檔案放在APP-INF/classes中,這些類檔案和JAR檔案會被root classloader進行裝載,可以被多個應用共享;
第二:可以通過META-INF/MANIFEST.MF檔案來指定需要的classes。通常的用法是在META-INF/MANIFEST.MF檔案中增加Class-Path:一行。舉例如下:
Class-Path:/d:ejb/add.jar
這樣就會在當前的jar包中可以找到我們需要的add.jar檔案。需要說明的是,在Class-Path:行的最後一定要有一個換行,否則會發生錯誤。還有,通過Class-Path只能指定本地的JAR檔案。
如果能對應用伺服器的類裝載原理有了較清楚地瞭解,會對我們的應用移植,在開發中避免不必要的類裝載的錯誤會有很大的幫助。