將自定義標(biāo)記庫打包到 JAR 文件中,以便更安全和更容易地發(fā)布Brett McLaughlin
作者, O‘Reilly and Associates
2003 年 10 月 25 日
將標(biāo)記庫存放在本地文件系統(tǒng)中的確有利于內(nèi)部(in-house)開發(fā)和測試,但是這并非永遠(yuǎn)都是好的解決方案。自定義標(biāo)記庫應(yīng)該能夠被廣泛地訪問,也就是說,必須以一種標(biāo)準(zhǔn)的和安全的方式來發(fā)布它們。BrettMcLaughlin 解釋了如何將您的自定義標(biāo)記庫打包到 JAR 文件,以便在任何 JSP 兼容的 Web 容器中更容易地維護(hù)、發(fā)布和安裝它們。
到目前為止,我們在本系列中講到的都是自定義標(biāo)記庫在本地文件系統(tǒng)中的情況,在這種情況下,我們可以很容易地訪問和操作這些自定義標(biāo)記庫。然而,雖然本地訪問對于內(nèi)部(in-house)開發(fā)和設(shè)計來說很有用,但這并非永遠(yuǎn)都是一個好的解決方案。自定義標(biāo)記庫的最終目的就是它們應(yīng)該能夠被廣泛地訪問,這意味著必須以一種標(biāo)準(zhǔn)化的方式來發(fā)布自定義標(biāo)記庫,并且這種方式允許一些必要的安全措施。在本期的 JSP 最佳實踐中,您將學(xué)習(xí)如何將自定義標(biāo)記庫打包到一個 JAR 文件中,以便更安全和更容易地發(fā)布。
為什么使用 JAR?
自定義標(biāo)記庫本身就是要被發(fā)布的,既可能是在公司開發(fā)小組這么一個小圈子內(nèi)發(fā)布,或者是在聯(lián)合組織這樣更大的圈子內(nèi)發(fā)布,也可能是在面向付費客戶的外部網(wǎng)絡(luò)上發(fā)布。但不管是哪種情況,將標(biāo)記庫存放在本地文件系統(tǒng)中并使其在該位置可用,都不是一個好主意。
如果您的標(biāo)記庫是用于一個內(nèi)部(in-house)開發(fā)小組,那么在發(fā)布該標(biāo)記庫時您首先想到的就是要分清責(zé)任。在 JSP 編程中,理想的情況是擁有兩個并行工作的開發(fā)小組:Java 開發(fā)人員負(fù)責(zé)編寫實現(xiàn)細(xì)節(jié),而 JSP 頁面設(shè)計者則負(fù)責(zé)處理前端。但是經(jīng)驗表明,如果不強制執(zhí)行的話,這種分工很快就打破了。將自定義標(biāo)記庫放在一個可以從本地訪問的文件系統(tǒng)中這種做法會造成一種不利的情形,在這種情形下,即使是好意的行為 -- 例如 JSP 頁面設(shè)計者“改正” TLD 文件,或者 Java 程序員“調(diào)整” HTML -- 也可能給開發(fā)周期以及最終產(chǎn)品帶來破壞。
如果將遠(yuǎn)程方(例如外部公司或組織)這一因素也考慮進(jìn)來,那么這種情形就更加嚴(yán)重了。無論何時您允許不受控制的外方(例如最終用戶或者頁面設(shè)計者)訪問您的代碼,都將招致麻煩。例如,假設(shè)一個外部公司的用戶更改您的 TLD,或者搞亂標(biāo)記類文件。這樣一來,您不但要因為產(chǎn)生的錯誤而受到責(zé)備,而且很可能找不出到底是誰犯下這樣的錯誤。您將花費雙倍的時間來調(diào)試代碼,而實際上問題的起因不過是一個用戶錯誤。這種類型的錯誤往往不止出現(xiàn)一次 -- 只要您將主標(biāo)記庫存放在一個可以從本地訪問的文件系統(tǒng)中,這種錯誤就會重復(fù)出現(xiàn)。
最后,讓我們考慮一下,如果您決定將自定義標(biāo)記庫推向市場進(jìn)行出售,會出現(xiàn)什么情況呢?現(xiàn)今,對類進(jìn)行反編譯十分容易,這就意味著某些人可以輕易地買到您的代碼,加以修改,然后惡意地以您公司的名義使用它?;蛘?,他們可以簡單地重新打包它,將其放在他們自己的網(wǎng)站上出售。不管是哪種情形,對于您來說都不是什么好事。將代碼打亂(這使得反編譯二進(jìn)制代碼變得很難,而且通常是不可能的)是避免惡意修改或者剽竊的好方法。將您的標(biāo)記庫打包到一個單獨的、離散的單元中也是推薦的做法。
JSP 規(guī)范允許我們使用 Java 平臺的 JAR 工具打包自定義標(biāo)記庫。一旦這些自定義標(biāo)記庫被打包到 JAR 文件中,就可以廣泛地發(fā)布、維護(hù)和安裝。而且,您將看到,將標(biāo)記庫打包到 JAR 文件中并不很難。
創(chuàng)建標(biāo)記庫目錄
第一步就是像清單 1 顯示的那樣創(chuàng)建一個標(biāo)記庫目錄結(jié)構(gòu):
清單 1. 用于標(biāo)記庫 JAR 的目錄結(jié)構(gòu)$basedir/ META-INF/ META-INF/site-utils.tld com/ com/newInstance/ com/newInstance/site/ com/newInstance/site/tags/ com/newInstance/site/tags/LastModifiedTag.class com/newInstance/site/tags/SSOSubmitTag.class com/newInstance/site/tags/CopyrightTag.class com/newInstance/site/utils/HTMLParser.class com/newInstance/site/utils/RegExp.class
|
您可以在自己的 Web 容器中創(chuàng)建這樣的目錄結(jié)構(gòu),步驟如下:
- 為您的標(biāo)記庫創(chuàng)建一個名為 tag-libraries 的基目錄。
- 在 tag-libraries 目錄中,創(chuàng)建一個名為 META-INF 的子目錄。
- 從 Web 應(yīng)用程序的 WEB-INF/tlds 目錄中,將您想要的 TLD 文件復(fù)制到這個 META-INF 目錄中。
- 從 WEB-INF/classes 目錄中將您想要的包結(jié)構(gòu)復(fù)制到基目錄中。
確信您只對標(biāo)記庫用到的目錄和類進(jìn)行了復(fù)制 -- 因為您最終想要完成就是將自己的 Java 類與您的標(biāo)記一起發(fā)布。
創(chuàng)建 JAR 文件
接下來的一步是使用 Java 命令 jar
,從您的標(biāo)記庫目錄結(jié)構(gòu)創(chuàng)建一個 JAR 文件,如清單 2 所示:
清單 2. 創(chuàng)建 JAR 文件[legolas:tqag-libraries] bmclaugh% jar cvf newInstance-taglib_1-1.jar META-INF comadded manifestadding: com/(in = 0) (out= 0)(stored 0%)adding: com/newInstance/(in = 0) (out= 0)(stored 0%)adding: com/newInstance/site/(in = 0) (out= 0)(stored 0%)adding: com/newInstance/site/tags/(in = 0) (out= 0)(stored 0%)adding: com/newInstance/site/tags/CopyrightTag.class(in = 980) (out= 382)(deflated 39%)adding: com/newInstance/site/tags/LastModifiedTag.class(in = 1488) (out= 818)(deflated 45%)adding: com/newInstance/site/tags/SSOSubmitTag.class(in = 2208) (out= 1060)(deflated 48%)adding: META-INF/(in = 0) (out= 0)(stored 0%)adding: META-INF/site-utils.tld(in = 589) (out= 334)(deflated 43%)
|
只要您原意,產(chǎn)生的 JAR 文件可以傳遞給任何人 -- 無論是公司內(nèi)部的頁面設(shè)計者,還是一家海外公司。
文檔編制和版本控制
創(chuàng)建任何標(biāo)記庫的重要一環(huán)是文檔編制 -- 您 要為您的代碼編制文檔,對不對? -- 當(dāng)需要打包標(biāo)記庫以用于發(fā)布的時候,更是如此。您或許已經(jīng)注意到,前面的 JAR 中包括注釋 added manifest
,這條注釋引用由 JAR 規(guī)范定義的一個特殊類型的文件。 manifest 是一種文本文件,其中存有關(guān)于一個 JAR 的信息,這個文件總是被包括在 JAR 內(nèi)的同一個地方。如果您想知道一個 Java 歸檔文件的內(nèi)容或者功能,那么首先(最好)要看的就是 manifest 文件。
在本例中,manifest 包括一個版本標(biāo)識(VID),這讓您可以跟蹤您的工作與最終用戶或頁面設(shè)計者的已有 JAR 文件之間的修訂和升級。
清單 3 展示了一個用于標(biāo)記庫的簡單 manifest 文件:
清單 3. 一個簡單的 manifest 文件Name: com/newInstance/site/tags/Sealed: trueImplementation-Title: "newInstance.com Site Utility Tag Library"Implementation-Version: "1.1"Implementation-Vendor: "Brett McLaughlin"
|
上面的 manifest 文件定義了要發(fā)布的 Java 包的名稱,并規(guī)定 JAR 文件應(yīng)該 密封(seal)起來。將一個文件密封起來可以確保 com.newInstance.site.tags
包中的所有類都 必須存在于同一個 JAR 文件中。自然地,這樣可以防止用戶創(chuàng)建他自己的類,將這些類分派給同一個包,并覆蓋或擴展這些類的功能。密封是一種好的習(xí)慣,可以確保代碼的一致性和版本控制。
將 manifest 添加到 JAR 中
最后一步是為標(biāo)記庫包提供一個名稱、版本和提供者(provider)。您所提供的信息將可以很容易地被任何 JAR 工具訪問到,并且使得您可以更容易地判斷您是否需要為用戶升級該標(biāo)記庫。
清單 4 展示了如何在創(chuàng)建時將 manifest 添加到 JAR 文件中。這里的文件名是 manifest.mf,但是您也可以使用任何您選擇的文件名。
清單 4. 創(chuàng)建一個帶有 manifest 的 JAR 文件[legolas:tqag-libraries] bmclaugh% jar cvfmnewInstance-taglib_1-1.jar manifest.mf META-INF comadded manifestadding: com/(in = 0) (out= 0)(stored 0%)adding: com/newInstance/(in = 0) (out= 0)(stored 0%)adding: com/newInstance/site/(in = 0) (out= 0)(stored 0%)adding: com/newInstance/site/tags/(in = 0) (out= 0)(stored 0%)adding: com/newInstance/site/tags/CopyrightTag.class(in = 980) (out= 382)(deflated 39%)adding: com/newInstance/site/tags/LastModifiedTag.class(in = 1488) (out= 818)(deflated 45%)adding: com/newInstance/site/tags/SSOSubmitTag.class(in = 2208) (out= 1060)(deflated 48%)adding: META-INF/(in = 0) (out= 0)(stored 0%)adding: META-INF/site-utils.tld(in = 589) (out= 334)(deflated 43%)
|
創(chuàng)建標(biāo)記庫 URI
創(chuàng)建好 JAR 文件之后,您將需要讓頁面設(shè)計者知道如何從他們的 Web 容器鏈接到該 JAR 文件。類似于文件系統(tǒng)中的文件,最容易的方法就是創(chuàng)建一個 URI(統(tǒng)一資源標(biāo)識符),并將其存放在一個 web.xml 文件中。清單 5 展示了用于標(biāo)識一個標(biāo)記庫的 web.xml 條目:
清單 5. 在 web.xml 中標(biāo)識一個標(biāo)記庫<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"><web-app> <taglib> <taglib-uri> http://www.newInstance.com/taglibs/site-utils </taglib-uri> <taglib-location> /WEB-INF/lib/newInstance-taglib_1-1.jar </taglib-location> </taglib></web-app>
|
您可能已經(jīng)注意到,我們將 JAR 文件放在目標(biāo) Web 應(yīng)用程序的 WEB-INF/lib 目錄中。Web 應(yīng)用程序所使用的所有 JAR 文件都應(yīng)該存放在這個目錄中。這里不再像以前那樣引用文件系統(tǒng)上的 TLD 文件,web.xml 文件現(xiàn)在指向包含標(biāo)記庫的 JAR 文件。
結(jié)束語
通過這里羅列出來的簡單幾步,我們就將標(biāo)記庫從一般的文件系統(tǒng)轉(zhuǎn)移到一種受到更多控制的、可分發(fā)的 JAR 文件環(huán)境中。訪問 JAR 中的標(biāo)記庫與訪問 JAR 文件之外的文件系統(tǒng)中的標(biāo)記庫是一樣的:您只需簡單地在一個 taglib
指令中指定 URI,并運行該指令。
在接下來的幾期技巧文章中,我們將超越這些 JSP 基礎(chǔ)知識,了解一些特定于 Web 的 JSP 功能。這些技巧的主題涉及從使用數(shù)據(jù)庫到處理動態(tài)導(dǎo)航鏈接,這些技巧將為基于 Java 的 Web 站點和 Web 應(yīng)用程序帶來精彩的一面。
參考資料
- 您可以參閱本文在 developerWorks 全球站點上的 英文原文.
- 剛開始學(xué)習(xí) JSP 技術(shù)嗎?請參閱由 Brett McLaughlin 撰寫的 JSP最佳實踐 系列 前面的文章。
- 您可能還想了解一些適合于開發(fā) JSP 的 IDE。下面這幾個 IDE 可供選擇:
您可以在 java.sun.com 上學(xué)習(xí)更多關(guān)于 Java 歸檔(JAR) 工具的知識。
對于那些剛剛接觸 JAR 的人來說,這里是另一篇很好的 Java 歸檔工具簡介。
Noel Bergman 撰寫的 “ JSP 標(biāo)記庫: 通過設(shè)計獲得更好的適用性” ( developerWorks, 2001年12月) 介紹了自定義標(biāo)記庫工具,它支持 JSTL 的創(chuàng)建。
Jeff Wilson 撰寫的 “ 使用自定義標(biāo)記控制 JSP 頁面”( developerWorks,2002年1月) 是有關(guān)自定義標(biāo)記庫通信的入門文章。
有關(guān) JSP 技術(shù)的指導(dǎo)性介紹,參閱 Noel Bergman 的教程 “ JavaServer Pages 技術(shù)簡介” ( developerWorks, August 2001).
要了解 JSP 的瑣碎細(xì)節(jié),最好的辦法是 閱讀 JSP 規(guī)范。
Hans Bergsten 撰寫的 JavaServer Pages (O‘Reilly & Associates, 2002) 是學(xué)習(xí) JSP 技術(shù)不可或缺的參考資料。
JSP 技術(shù)是基于Java Servlets 技術(shù)的。Jason Hunter 的 Java Servlet 程序設(shè)計 (O‘Reilly & Associates, 2002)是學(xué)習(xí) servlets 的好資料。
請參閱 developerWorks Java 技術(shù)教程頁面 ,獲取免費教程的完整列表。
在 developerWorks Java 技術(shù)專區(qū) 中可以找到數(shù)百篇有關(guān) Java 編程各個方面的文章(包括有關(guān) JSP 技術(shù)的更多文章)。 
關(guān)于作者 Brett McLaughlin 從 Logo 時代(還記得那個小三角嗎?)就開始從事計算機工作了。他現(xiàn)在專門研究用 Java 和 Java 相關(guān)技術(shù)構(gòu)建應(yīng)用程序基礎(chǔ)結(jié)構(gòu)。最近幾年,他在 Nextel Communications 和 Allegiance Telecom Inc. 從事這些基礎(chǔ)結(jié)構(gòu)的實現(xiàn)。Brett 是 Java Apache 項目 Turbine 的共同創(chuàng)始人之一,該項目通過使用 Java servlet 為 Web 應(yīng)用程序開發(fā)構(gòu)建可再用的組件體系結(jié)構(gòu)。他還是 EJBoss 項目(一種開放源碼 EJB 應(yīng)用程序服務(wù)器)和 Cocoon(一種開放源碼 XML Web 發(fā)布引擎)的志愿開發(fā)者之一??梢酝ㄟ^ brett@oreilly.com 與 Brett 聯(lián)系。 |