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