Servlet 2.5的新特徵

2005年9月26日,Sun公司和JSR154的專家組發佈Servlet API的一個新的版本。在一般情況下,一個JSR的新版本僅僅包括對以前少數有名無實的規範進行去除更新。但這次,新版本中增加新的特徵和變化,他們對Servlets的產生重要影響,使得Servlet的版本升到了2.5。

在這篇文章裏,我主要談談Servlet2.5版本中的新特徵。描述每一個變化,闡述那些必要變化產生的背景,並展示如何在基於Servlet的項目中利用這些變化。

事實上,這是我爲JavaWorld提供的第六篇關於Servlet API更新資料的文章。這篇文章意在兩個目的:從眼前來看,向你介紹Servlet的新特徵。從長遠來看,是展現Servlet變化的歷史概要,這樣當你基於老的Servlet API版本進行編碼的時候,你可以正確地決定哪些特徵和功能你可以使用,而哪些特徵和功能你不應該使用。你可以參考我先前寫的關於Servlet的文章。

注意:當你想實踐這些Servlet的新特徵和功能時,你要知道的是:並不是所有的Servlet容器和Java企業級應用服務器都能立即適用於最新版的Servlet API,寫這篇文章時(2006年1月2日),Jetty 6 server和Sun公司的GlassFish server是公認最好的支持Servlet2.5的容器,而Apache Tomcat5.5和Jboss 4.0目前只支持Servlet2.4。

版權聲明:任何獲得Matrix授權的網站,轉載時請務必保留以下作者信息和鏈接
作者:evenbetter
原文:http://www.javaworld.com/javaworld/jw-01-2006/jw-0102-servlet.html
譯文:http://www.matrix.org.cn/resource/article/44/44208_Servlet+2.5.html
關鍵字:Servlet;2.5

Servlet2.5一些變化的介紹:
1)        基於最新的J2SE 5.0開發的。
2)        支持annotations 。
3)        web.xml中的幾處配置更加方便。
4)        去除了少數的限制。
5)        優化了一些實例

J2SE 5.0的產物

從一開始,Servlet 2.5 規範就列出J2SE 5.0 (JDK 1.5) 作爲它最小的平臺要求。它使得Servlet2.5只能適用基於J2SE 5.0開發的平臺,這個變動意味着所有J2SE5.0的新特性可以保證對Servlet2.5程序員有用。
傳統意義上,Servlet和JEE版本一直與JDK的版本保持同步發展,但是這次,Servlet的版本跳過1.4版本。專家組認爲版本的加速增長是正當的,因爲J2SE5.0提出一個引人注目的,Servlet和JEE規範都要利用的特徵—Annotations。

Annotations
Annotations是作爲JSR175的一部分提出的(一種爲Java語言設計提供便利的Metadata)一種新的語言特色。它是利用Metadata爲Java編碼結構(類,方法,域等等)裝飾的一種機制。它不能像代碼那樣執行,但是可以用於標記代碼,這個過程是基於Metadata信息的代碼處理機,通過更新他們的事件行爲來實現的。

我們可以憑藉不同的技巧來註釋類和方法,例如連續地標記接口或者是@deprecated Javadoc評論。這種新式的Metadata可以便利地提供了一種標準的機制來實現註釋功能,以及通過庫來創建用戶自己的註釋類型的變量。

下面是一個簡單的Web service 註釋例子:

import javax.jws.WebService;
import javax.jws.WebMethod;
@WebService
public class HelloWorldService {
  @WebMethod
  public String helloWorld() {
    return "Hello World!";
  }
}



@WebService和@WebMethod這兩個註釋類型,在JSR181(爲Java平臺提供的Web ServicesMetadata)有詳細說明,可以像類一樣的引用,標記這個類作爲一個Web service並且標記它的helloWorld()方法做爲一個Web service方法。對於他們本身來說,註釋只是寫在那裏並沒有什麼作用,好像在崗位上做記錄一樣,但是,一個容器一旦加載這個類並對那些註釋進行二進制編碼,就可以把這個類連到Web service上。
註釋可以接受屬性/值這些參數。它保存着參數的信息並且可以利用這些參數來更改被請求的事件行爲。例如下面更高級的註釋例子:

@WebService(
 name = "PingService",
  targetNamespace=http://acme.com/ping
)
@SOAPBinding(
  style=SOAPBinding.Style.RPC,
  use=SOAPBinding.Use.LITERAL
)
public class Ping {
  @WebMethod(operationName = "Foo")
  public void foo() { }
}




一旦加載了這個類,一個正確配置的容器就會識別出注釋及其參數,並將這個做爲一個PingService通過利用remote-procedure-call/literal的編碼方式與一個Foo operation相連。實際上,註釋便指明瞭類和類的容器之間的聯繫。

Java本身的規範(JSR175)僅僅有少量的註釋類型變量。而這些有趣的註釋類型變量主要來自於其他的JSRs:
·JSR 250: Java平臺的公共註釋
·JSR 220: 企業級JavaBeans 3.0
·JSR 224: 基於XML的Java API Web Services (JAX-WS) 2.0
·JSR 181: Java平臺的Web Services Metadata

Servlet2.5中的註釋:
回到Servlet2.5上來,一種新的規範描述了幾種註釋在Servlet環境中是如何工作的。功能弱的Servlet容器忽略了這些規範,然而JEE容器中的Servlet卻嚴格遵守這些規範。
有的註釋提供了在XML註冊的可選擇性,否則就要註冊在配置文件web.xml中。有的作爲容器的請求來執行其任務,否則就由Servlet親自來執行。還有的註釋兩者都具備。


註釋準確的定義不是完全固定的,因爲Servlet本身並沒有定義註釋。它僅僅解釋了它們如何影響Servlet環境,下面是註釋的一個簡要的概述,你可以看到在JEE5中它們的用途:

·@Resource and @Resources:@Resource位於類或變量中以對Servlet容器進行“資源注入”。當容器識別出這個註釋時,它會在獲得服務地位之前,用適當的值實現帶註釋的變量的重新注入。通過使用這種註釋,你不必利用JNDI來查找命令和在配置文件web.xml中手動聲明資源。服務器通過Servlet的自我調整來執行它的任務。變量的名稱和類型由映像機制自動確定,儘管你可以利用註釋的參數來超越這一限制。一個注入的資源可以是數據源,Java信息服務目的文件或者是環境設置的標量。下面是一個例子:

@Resource javax.sql.DataSource catalog;
public getData() {
  Connection con = catalog.getConnection();
}


現在,在這段Servlet代碼變成服務之前,容器會定位JNDI變量,並對於目錄變量進行手動分配。
爲了效率,僅僅某些類支持資源注入,這些類有:Servlets,Servlet過濾器,Servlet事件監聽器,JSP標籤操作器,JSP庫事件監聽器,用於處理beans的JSF,以及一些與Serlvets無關的類。

·@Resources註釋與@Resource相似,但是它用於一組@Resource註釋。它們都來自JSR250,是Java平臺的公共註釋。

·@PostConstruct and @PreDestroy:可以使方法成爲帶有生命週期的方法。@PostConstruct方法用於資源注入初始化之後。@PreDestroy方法用於Servlet脫離服務並釋放注入的資源的時候。回收的方法必須是事實的方法,返回void並且不可以拋出任何異常。這些註釋本質上使得任何方法都成爲init()和destroy()的子方法,這些特徵也來自與JSR250。

·@EJB:類似於@Resource,設計用於注入企業級的JavaBeans。比起@Resource,它略有不同,在於@EJB的參數特定設計用來定位EJB的參數。這個註釋來自EJB3.0的規範。

·@WebServiceRef:與@Resource 和 @EJB相似,設計用於注入Web service參數。來自於JAX-WS2.0規範。

·@PersistenceContext, @PersistenceContexts, @PersistenceUnit, and @PersistenceUnits:這些註釋來自EJB3.0規範來支持Java對象的持久化。

·@DeclareRoles: 定義應用程序中安全角色的使用。當定義一個Servlet類時,在配置文件web.xml中<security-role>標籤中對它進行設置,來自JSR250。

· @RunAs:用於聲明哪個類應該執行。當定義一個Servlet類時,在配置文件web.xml中<run-as>標籤中對它進行設置。來自於JSR250。

Annotation的效率
不論你使用註釋與否——尤其在你不使用時——它對於理解服務器上程序的執行有着重要意義。爲了讓服務器識別類中的註釋,它必須加載這些類,這就意味着服務器必須是啓動着的,服務器通過WEB-INF/classes目錄下和WEB-INF/lib目錄下的所有類文件來查找註釋。(每個規範下,服務器不必查找這兩個目錄以外的目錄。)你可以通過下面的方法指明<web-app>根的屬性而不必使用如何進行註釋:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
                 version="2.5" full="true">
</web-app>



web.xml的便利

Servlet2.5對於web.xml引入幾個小的變動,使得它更加方便。

Servlet名稱的通配符化
首先,當你寫<filter-mapping>,你現在可以在<Servlet-name>標籤中使用*號來代表所有的Servlets。而以前,你必須一次把一個Servlet綁定到過濾器上,像這樣:

<filter-mapping>
  <filter-name>Image Filter</filter-name>
  <Servlet-name>ImageServlet</Servlet-name>
</filter-mapping> 



現在,你可以一次綁定所有的Servlets:

<filter-mapping>
  <filter-name>Image Filter</filter-name>
  <Servlet-name>*</Servlet-name>  <!—新特徵 -->
</filter-mapping>



這有着很大用途,例如:

<filter-mapping>
  <filter-name>Dispatch Filter</filter-name>
  <Servlet-name>*</Servlet-name>
  <dispatcher>FORWARD</dispatcher>
</filter-mapping>



映射的複合模式
其次,當我們寫<Servlet-mapping> 或者 <filter-mapping>時,你現在可以在同一的標籤中採用複合匹配的標準。以前一個<Servlet-mapping>只支持一個<url-pattern>元素,現在它不只支持一個,例如:

<Servlet-mapping>
  <Servlet-name>color</Servlet-name>
  <url-pattern>/color/*</url-pattern>
  <url-pattern>/colour/*</url-pattern>
</Servlet-mapping>



同樣地,以前<filter-mapping>也是隻支持一個<url-pattern> 或者一個 <Servlet-name>。現在它對於每個元素都可以支持任意多個:

<filter-mapping>
  <filter-name>Multipe Mappings Filter</filter-name>
  <url-pattern>/foo/*</url-pattern>
  <Servlet-name>Servlet1</Servlet-name>
  <Servlet-name>Servlet2</Servlet-name>
  <url-pattern>/bar/*</url-pattern>
</filter-mapping>



HTTP方法名
最近,你可以將合法的HTTP/1.1方法名放進<http-method>元素中。當你使用這些方法時,<http-method>將指明<security-constraint>標記裏的方法應該被應用。從以前來看,它僅限於HTTP/1.1的7個標準方法:GET,POST,PUT,DELETE,HEAD,OPTIONS和TRACE。但是,HTTP/1.1允許對方法進行擴展,WebDAV是用於這種擴展的普遍技術。在Servlet2.5中,你可以安全地約束任何可能的HTTP方法名,標準及擴展,包括WebDAV方法,例如:LOCK,UNLOCK,COPY及MOVE。
如果你寫一個WebDAV的Servlet,你不必使用doLock()和doCopy()方法。你必須寫自己的service()方法及分派request.getMethod()方法。正由於這種變化,你不必管理系統的安全性。

去除限制

Servlet2.5去除了關於錯誤處理和回話跟蹤的一些限制。對於錯誤處理,Servlet2.5之前,配置在<error-page>中的錯誤處理頁面不能通過調用setStatus()方法來修改觸發他們的錯誤代碼,而Servlet2.5減弱了這一規範。這樣的規範的產生於這樣的觀點,就是錯誤頁面的工作是指出每個錯誤而不是修改錯誤。但是,實際使用中,錯誤頁面不只是用於指出錯誤,而是還能做更多的事情,或許可以代替在線幫助來幫助用戶解決問題。這個規範將不再限制錯誤頁面所產生的反饋信息。

對於會話跟蹤,Servlet2.5之前,調用RequestDispatcher.include()的Servlet不能設置響應的標題頭,而Servlet2.5減弱了這一規範。原規範的目的是使內部的Servlets限制在自己的頁面空間中,不可以影響外部的頁面。現在這個規範已經減弱,允許在內部的Servlet中使用request.getSession()命令,這個命令可以悄悄地創建一個會話跟蹤cookie的標題頭。邏輯上要求限制內部的資源,但邏輯上也要求這些限制不應該取消其啓動session的這一功能。這個變動對於Portlet規範來說顯得尤其重要。作用是:如果響應已經有效,則getSession()命令就會拋出一個IllegalStateException(異常),而在此之前,就沒有這個功能。

Clarifications
最近,新的規範對一些邊緣方法進行了說明,使得Servlets更加方便而且保證了更好地按要求工作。

終止響應
第一處說明細小又深奧,但做爲規範中的一個例子還有蠻有趣的。Servlet2.4規範規定響應在這幾種情況下應該是有效的,包括:在響應的setContentLength方法中內容已經明確說明,以及內容已經寫進了響應中。這種情況只有你的代碼像下面這樣纔可以使響應重新定向:

response.setHeader("Host", "localhost");
response.setHeader("Pragma", "no-cache");
response.setHeader("Content-Length", "0");
response.setHeader("Location", "http://www.apache.org");



Servlet技術忽略特定區域的標題頭,因爲內容滿足0字節長度,響應就會立即生效。而在它開始之前,響應就已失效了!Servlet容器通常拒絕執行這種行爲,而Servlet2.5版本增加了“長度必須大於0”這個原則。

實例編碼
Servlet2.4規範規定必須在調用request.getReader()方法之前調用request.setCharacterEncoding()方法。但是,如果你忽略這個原則而在其之後去調用request.setCharacterEncoding()方法,那麼會產生什麼後果,這個問題規範裏並沒有說。爲了簡便,現在消除這種情況!

Cross-context sessions(不同上下文目錄間的會話)
最近,關於Cross-context會話處理的規則已經明確說明。當Servlets指派從一個上下文到其他上下文的請求時,這個規則就發揮了作用——在目標調用過程中,包括哪些會話。這個版本的出現使得一個上下文目錄的主頁裏的portlets可以通過幾種內部的命令來對別的上下文目錄裏的portlets起作用。Servlet2.5明確指出一個上下文目錄裏的資源可以訪問其他上下文目錄的session(會話),而不用考慮這個請求從哪裏開始的。這意味着portlets可以脫離主頁的範圍而在自己的範圍裏運行,而且這個規範還會應用在不兼容的Serlvet容器中。

期待
由於Servlet2.5版本要保持一些舊的性質,幾個大的概念不得不延後到下一個階段。它們包括:
·新的輸入/輸出(NIO)支持:使NIO通道更有利於Servlets進行客戶端通信成爲可能。
·過濾器wrap-under或wrap-over語義:有時用過濾器包裝請求,和/或者響應對象去修改方法行爲或者啓用新的方法。當把這種包裝和服務器對請求和響應的包裝結合起來時,又應該怎麼包裝在一起?
·用於歡迎的Servlets文件:做爲索引應該充當歡迎作用的文件嗎?在此之前,這個回答是肯定的。但是規範沒有明確說明如何使用這個功能,尤其在沒有索引的情況下。
·用於歡迎的文件的分派規則:如何分派歡迎文件,這個細節並沒有完全說明,而是遺留了一些開放的缺口來應對不兼容問題。
·登陸後選擇默認頁面:如果用戶通過他們的書籤訪問Servlet的登陸頁面,那麼在成功登陸後頁面應該轉向哪裏呢?這個問題至今尚未明確說明。
·用戶的主題日誌:在通過網站正確地註冊之後,不通過傳統地登陸方式沒有辦法使Servlet信任用戶。

結束語
如果拋開註釋來看Servlet2.5的變化,可見在配置文件web.xml中去除了一些限制,是有利的,同時又優化了實例行爲使其更適合更便於開發Web系統(網頁)。
Servlet2.5中註釋的作用更加戲劇化。Servlets本身不能聲明註釋類型的變量,甚至性能弱的Servlet容器都不支持註釋。然而在JEE5環境下的Servlets編寫者可以看到,通過公共的註釋及EJB3.0和JAX-WS2.0規範而引入的註釋類型會對代碼產生很大變化,並且這也將對Servlet如何管理外部資源,對象的持久化及EJB的構成產生重大影響。

關於作者
Jason Hunter:《Java Servlet Programming, 2nd Edition》的作者,於他人合著了《Java Enterprise Best Practices》。他是Apache組織的成員,是Java 公共過程執行委員會的Apache代表,併爲Java的開源制定了具有里程碑意義的協議。他是Servlets.com的發行人,也是最早爲Apache Tomcat投稿的人之一,還開發了開源的JDOM library來優化java和XML的整合。他還設計開發了CountryHawk,這個產品可以根據用戶的IP地址快速地確定用戶的所在國。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章