J2EE應(yīng)用部署(3):高級篇
發(fā)表時(shí)間:2024-06-10 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]提綱: =================================== 一、模塊次序問題 二、依賴庫的問題 2.1 解決方案之一 2.2 解決方案之二 2.3 依賴庫應(yīng)用實(shí)例 =================================== 正文: =====...
提綱:
===================================
一、模塊次序問題
二、依賴庫的問題
2.1 解決方案之一
2.2 解決方案之二
2.3 依賴庫應(yīng)用實(shí)例
===================================
正文:
===================================
在前面兩篇文章中,我們了解了J2EE應(yīng)用封裝和部署的基本概念和實(shí)踐操作,下面我們來看看幾個(gè)可能遇到的問題。
一、模塊次序問題
J2EE規(guī)范沒有對EAR文件內(nèi)的J2EE模塊應(yīng)該如何部署作出任何規(guī)定。特別地,J2EE規(guī)范沒有明確規(guī)定部署模塊的次序。如果一個(gè)模塊中的某個(gè)組件要用到另一個(gè)待部署模塊的組件,它可能會帶來問題。
因此,必須注意大多數(shù)應(yīng)用服務(wù)器以如下步驟部署EAR文件:
EAR文件內(nèi)的所有資源適配器作為基本連接器部署。如果存在多個(gè)資源適配器,則它們的部署次序就是它們在application.xml部署描述器中列出的次序。
部署所有EJB模塊。由于EJB可能在初始化期間用到某些資源適配器,所以EJB的部署在資源適配器之后。如果存在多個(gè)EJB模塊,它們的部署次序?qū)⑹撬鼈冊赼pplication.xml中列出的次序。
部署所有Web應(yīng)用模塊。由于Web應(yīng)用初始化期間可能用到資源適配器和EJB,所有Web應(yīng)用在這兩者之后部署。如果存在多個(gè)Web應(yīng)用模塊,它們部署次序就是它們在application.xml中列出的次序。
二、依賴庫的問題
在J2EE應(yīng)用封裝和部署過程中,最常見的問題出現(xiàn)在工具類和支持類上。封裝Web應(yīng)用或EJB應(yīng)用時(shí),這些庫應(yīng)該放在哪里?Web應(yīng)用和EJB應(yīng)用一般都有被“卸出”(這里指裝入的反向過程)的能力,這種能力由部署時(shí)裝入它們的類裝載器支持。如果我們把工具類和支持類放入應(yīng)用服務(wù)器的標(biāo)準(zhǔn)類路徑,這些類很可能完全失去被卸出的能力。這樣,如果Web應(yīng)用或EJB應(yīng)用要更新某個(gè)庫的版本,重新部署Web應(yīng)用或EJB應(yīng)用時(shí),包含工具類和支持類的依賴庫也要重新部署。在這種情形下,把工具類放入應(yīng)用服務(wù)器標(biāo)準(zhǔn)類路徑很不方便,因?yàn)槊看尾渴餡eb應(yīng)用和EJB應(yīng)用時(shí),都要重新啟動整個(gè)應(yīng)用服務(wù)器,這顯然不是理想的選擇。
那么,在J2EE標(biāo)準(zhǔn)定義中,假定依賴庫放在哪里才能實(shí)現(xiàn)運(yùn)行時(shí)的重新部署(熱部署)呢?有兩個(gè)簡單的方案,但從根本上來說兩者都不甚合理:
以JAR文件形式封裝的依賴庫可以放入Web應(yīng)用的WEB-INF\lib目錄。一般地,WEB-INF\lib目錄基本上只用來存放Servlet,JSP頁面和Servlet會在讀取新類時(shí)尋找該目錄。如果工具類庫只供一個(gè)Web應(yīng)用的JSP頁面和Servlet使用,應(yīng)該說這個(gè)方案已經(jīng)足夠。然而,如果EJB組件、JMS消費(fèi)者、啟動應(yīng)用的類和關(guān)閉應(yīng)用的類也要用到同一工具類庫,這種方案不再有效,因?yàn)閷τ谒鼈儊碚f,WEB-INF\lib目錄是不可見的。
除了把工具類庫放入WEB-INF\lib目錄之外,同時(shí)在每一個(gè)EJB JAR文件中包含一份完整的拷貝。部署EJB時(shí),EJB類裝載器將只在它自己的JAR文件中尋找被引用的工具類,不去查看其他已部署EJB應(yīng)用的JAR文件和WEB-INF\lib目錄。如果有幾個(gè)EJB應(yīng)用都要用到同一個(gè)工具類庫,則在每一個(gè)JAR文件中放入該類庫的一份拷貝就能解決問題。雖然這種方案實(shí)現(xiàn)了依賴庫的熱部署能力,但它明顯地不夠完善。封裝JAR文件的目的是為了提高應(yīng)用的模塊化程度,把同一個(gè)類文件放入多個(gè)JAR包正好是背其道而行之。此外,多次復(fù)制同一組類無謂地加大了應(yīng)用的體積。最后,即使只改變一個(gè)庫,每一個(gè)JAR文件也都要重新構(gòu)造,從而使構(gòu)造過程復(fù)雜化。
下面我們來看兩種較為有效的解決方案。
2.1 解決方案之一
要解決這個(gè)問題,一種可能的方案是在J2EE中避免使用多個(gè)JAR文件,把所有EJB和工具類聚集成單個(gè)包。EJB 2.0規(guī)范正在推動幾個(gè)項(xiàng)目進(jìn)行這方面的工作。這個(gè)規(guī)范要求參與關(guān)系的實(shí)體EJB使用本地引用,因此參與關(guān)系的各個(gè)EJB必須封裝到同一個(gè)JAR文件。
由于新的規(guī)范要求避免使用遠(yuǎn)程關(guān)系,因此,許多供應(yīng)商正在考慮提供能夠把多個(gè)EJB JAR文件合并的工具。這些工具能夠讀取兩個(gè)合法的EJB JAR文件,把它們的類和部署描述器合并成單個(gè)統(tǒng)一的包。但應(yīng)當(dāng)注意的是,即使所有EJB組件都聚合到了單個(gè)JAR文件里面,避免了在多個(gè)EJB之間復(fù)制依賴庫,但如果Web應(yīng)用也要用到依賴庫,則WEB-INF\lib目錄下仍舊需要依賴庫的副本。
此外,對EJB應(yīng)用模塊化的需求仍舊存在,許多人希望能夠單個(gè)地部署EJB。因?yàn)橹匦虏渴鹨粋(gè)JAR文件時(shí),該JAR文件內(nèi)的每一個(gè)EJB都將重新部署,如果實(shí)際要部署的只是單個(gè)EJB,部署過程中就會出現(xiàn)許多不必要的操作。
2.2 解決方案之二
隨著JDK 1.3的發(fā)布,Sun重新定義了支持可選包必不可少的“擴(kuò)展機(jī)制”。這個(gè)擴(kuò)展機(jī)制支持兩方面功能:
JAR文件可以聲明自己對其他JAR文件的依賴性。
類裝載器經(jīng)過了修改,能夠在可選的包和應(yīng)用路徑中搜索類。
J2EE 1.3規(guī)范要求應(yīng)用服務(wù)器必須提供這方面的支持。這就要求部署描述工具能夠裝載所有通過擴(kuò)展機(jī)制定義的可選庫。它同時(shí)也意味著,如果一個(gè)應(yīng)用服務(wù)器或部署工具能夠在運(yùn)行時(shí)卸出或重新部署那些通過擴(kuò)展機(jī)制使用庫的EJB應(yīng)用,那么,該應(yīng)用服務(wù)器或工具也支持所有依賴庫的卸出或重新部署。
這種擴(kuò)展機(jī)制為Web應(yīng)用WAR文件和EJB應(yīng)用JAR文件指定自己需要哪些企業(yè)應(yīng)用EAR文件中的依賴庫提供了一種標(biāo)準(zhǔn)化的方法。那么,這種擴(kuò)展機(jī)制是如何工作的呢?每一個(gè)JAR文件里都有一個(gè)manifest(意為載貨單、旅客名單)文件,這個(gè)文件由jar工具自動創(chuàng)建,默認(rèn)名字是manifest.mf。JAR文件可以在manifest文件中加入一個(gè)Class-Path屬性,引用它所依賴的JAR文件。我們可以手工編輯manifest.mf文件,在原有內(nèi)容的基礎(chǔ)上,添加Class-Path屬性。實(shí)際上,許多供應(yīng)商提供的EJB封裝工具會在封裝過程中處理依賴類,自動創(chuàng)建合適的manifest.mf文件,使這個(gè)文件包含正確的Class-Path屬性。
如果在創(chuàng)建EJB JAR文件時(shí)修改了manifest.mf,引入了Class-Path屬性,在生成一個(gè)新的EJB應(yīng)用文件時(shí),應(yīng)用服務(wù)器提供的容器生成工具必須保存這個(gè)值。在WebLogic Server 6.1下,如果EJB JAR已經(jīng)在manifest.mf文件中包含Class-Path屬性,weblogic.ejbc工具會在生成新EJB應(yīng)用時(shí)保存這個(gè)值。當(dāng)前,專門用來創(chuàng)建Class-Path屬性并把它插入manifest.mf的工具還沒有出現(xiàn),所以這個(gè)工作有時(shí)還需要通過手工編輯JAR文件的manifest文件進(jìn)行。
Class-Path屬性的值是用來搜索工具類庫的相對URL。這個(gè)URL總是相對于包含Class-Path屬性的組件(而不是EAR文件的根)。單個(gè)Class-Path屬性內(nèi)可以指定多個(gè)URL,一個(gè)manifest文件可以包含多個(gè)Class-Path屬性。Class-Path屬性的一般格式是:
Class-Path: 列出用空格分隔的多個(gè)JAR文件名字
下面是一個(gè)例子:
Class-Path: mylog4j.jar xmlnew.jar foo/bar/myutil.jar
在J2SE應(yīng)用中使用這種擴(kuò)展機(jī)制時(shí),Class-Path屬性可以引用目錄。然而,對于全部內(nèi)容都包含在JAR文件中的J2EE應(yīng)用,Class-Path屬性只能引用其他JAR文件。此外,在manifest文件中,Class-Path屬性聲明必須在一個(gè)獨(dú)立的行上,以便與其他屬性聲明區(qū)分。
這種擴(kuò)展機(jī)制的功能非常強(qiáng)大。特別地,通過創(chuàng)建一個(gè)以解析次序?yàn)樽罱K次序的、包含所有類的統(tǒng)一類路徑,它能夠方便地解決循環(huán)引用問題。例如,在下面這個(gè)例子中,假設(shè)首先被解析的是MyEJB1.jar。MyEJB1.jar引用了:
Class-Path: jaxp1.jar MyEJB2.jar ..\xmlnew.jar
此時(shí),類裝載器將解析MyEJB2.jar。MyEJB2.jar引用了:
Class-Path: jaxp1.jar MyEJB1.jar
類裝載器最終使用的“應(yīng)用級類路徑”將是:
Class-Path: jaxp1.jar MyEJB2.jar ..\xmlnew.jar MyEJB1.jar
2.3 依賴庫應(yīng)用實(shí)例
下面這個(gè)例子示范了一個(gè)企業(yè)應(yīng)用各種可能的類裝載情形。它示范了多個(gè)EJB模塊、多個(gè)Web應(yīng)用,以及在這些應(yīng)用之間多個(gè)共享的依賴庫。通過這個(gè)例子,我們可以了解應(yīng)用服務(wù)器從不同應(yīng)用裝載各個(gè)類的過程。當(dāng)應(yīng)用運(yùn)行時(shí),通過輸出不同類的類裝載器層次關(guān)系,我們可以了解:是否所有的類都通過單個(gè)類裝載器裝入,還是通過不同的類裝載器裝入;如果通過多個(gè)類裝載器裝入,這些裝載器有什么關(guān)系。
這個(gè)例子包含兩個(gè)EJB模塊、兩個(gè)Web應(yīng)用模塊、七個(gè)在不同情形下使用的依賴類庫。EAR文件的結(jié)構(gòu)如下:
MyDepend1-container.jar
MyDepend2-container.jar
MyWebApp1.war
MyWebApp2.war
TestUtil1.jar
TestUtil2.jar
TestUtil3.jar
TestUtil4.jar
TestUtil5.jar
TestUtil6.jar
TestUtil7.jar
META-INF\
application.xml
每一個(gè)“MyDepend?-container”JAR文件包含一個(gè)EJB。每一個(gè)Web應(yīng)用中包含一個(gè)名為TestServlet的Servlet。每一個(gè)工具類庫包含一個(gè)類,這個(gè)類有一個(gè)方法,它的功能是輸出類裝載器的層次關(guān)系。這個(gè)例子測試了EAR文件內(nèi)許多不同的類裝載情形,其中包括:
當(dāng)一個(gè)EJB用到一個(gè)依賴庫,且在EJB manifest里面的類路徑中引用它時(shí),它是如何裝載的?
當(dāng)不同EJB模塊內(nèi)的多個(gè)EJB共享一個(gè)依賴庫,且依賴庫通過各個(gè)EJB的manifest類路徑指定時(shí),它是如何裝載的?
當(dāng)Web應(yīng)用引用一個(gè)依賴庫,且通過Web應(yīng)用模塊的manifest路徑引用依賴庫時(shí),它是如何裝載的?
當(dāng)Web應(yīng)用引用一個(gè)依賴庫,且依賴庫保存在Web應(yīng)用模塊的WEB-INF\lib目錄下時(shí),它是如何裝載的?
當(dāng)一個(gè)EJB模塊和一個(gè)Web應(yīng)用都在它們的manifest路徑中引用一個(gè)依賴庫時(shí),依賴庫是如何裝載的?
要執(zhí)行這個(gè)例子,請先把MyDepend.ear文件(從本文后面下載源文件)部署到服務(wù)器上,然后運(yùn)行各個(gè)Web應(yīng)用的TestServlet。TestServlet將調(diào)用適當(dāng)?shù)腅JB方法,EJB的方法又調(diào)用依賴庫中類的方法。下面是執(zhí)行兩個(gè)Servlet的URL:
http://<服務(wù)器名字>:<端口>/web1/testservlet/
http://<服務(wù)器名字>:<端口>/web2/testservlet/
下面是Servlet運(yùn)行時(shí)在瀏覽器上的輸出:
WebLogic Server 6.1控制臺輸出如下:
下面是application.xml部署描述器:
Inc.//DTD J2EE Application 1.2//EN' 'http://java.sun.com/j2ee/dtds/application_1_2.dtd'>
App Name
MyDepend1-container.jar
MyDepend2-container.jar
MyWebApp1.war
web1
MyWebApp2.war
web2
第一個(gè)EJB模塊的manifest聲明的Class-Path屬性是:
Class-Path: TestUtil1.jar TestUtil3.jar TestUtil6.jar TestUtil7.jar
其他EJB模塊和Web應(yīng)用模塊的manifest類路徑聲明都有所不同,它們是EAR文件包含的七個(gè)依賴庫的不同組合。Web應(yīng)用中包含的各個(gè)Servlet提供有關(guān)執(zhí)行過程的詳細(xì)信息,具體請參見各個(gè)組件的源代碼。
毫無疑問,manifest.mf文件里面聲明的類路徑有助于提高J2EE應(yīng)用的模塊化。使用這種技術(shù)時(shí),我們可以通過一種簡單的模式確定哪些EJB應(yīng)該封裝為一個(gè)JAR文件,哪些應(yīng)該封裝為另一個(gè)JAR文件:
標(biāo)識出一個(gè)參與CMR(Container-Managed Relationship)關(guān)系的實(shí)體EJB。標(biāo)識出所有可以從這個(gè)源實(shí)體EJB通過CMR關(guān)系到達(dá)的實(shí)體EJB。把這個(gè)關(guān)系圖中的EJB封裝為一個(gè)EJB JAR。為每一組獨(dú)立的實(shí)體EJB關(guān)系重復(fù)這個(gè)過程。
把所有剩余的EJB分別封裝成JAR文件。
分析業(yè)務(wù)和技術(shù)方面的需求,如果有必要的話,把多個(gè)JAR文件合并成一個(gè)。如果修改單個(gè)EJB時(shí)重新部署多個(gè)EJB是可接受的,則可以用單個(gè)JAR文件封裝多個(gè)EJB。
每一個(gè)EJB JAR文件必須通過manifest的Class-Path列出其依賴關(guān)系。類裝載器將自動地解決循環(huán)引用和重復(fù)引用問題。例如,在前面演示依賴關(guān)系的例子中,多個(gè)EJB引用了第三個(gè)庫。但是,雖然存在這種重復(fù)引用,EAR類裝載器只裝載該庫一次。