Java
servlets 是一項被普遍接受的技術,用于構建基于 web 應用程序的動態內容;Servlet 3.0
規范早期草案版本的發行讓該技術在特性和應用程序接口(Application Program
Interface,API)方面得到了極大增強。Java Specification Request(JSR)已經以 JSR 315
的形式得到了批準,并計劃成為 Java Enterprise Edition 6(JSR
316)或更高版本的組成部分。與之前僅僅是維護發行版(maintenance releases)的一些版本規范不同,Servlet 3.0
規范隨帶了許多 web 開發新時代所需的最令人興奮的特性。在本文中,我們將研究新版 Java servlets
中引入的主要特性。值得注意的是,本規范仍處于草案版本階段,因此在本文中所討論的技術細節可能會發生變化。
新規范主要交付了以下新特性:
開發的簡易性
可插拔性和可擴展性
異步支持
安全性增強
其他雜項變化
很明顯,與其他技術相比,servlets 在 Java Enterprise Edition
家族中有著更廣泛的應用。Servlets 保留了其簡潔性和能夠處理 HTTP 請求并向 web 客戶機傳回響應的優點。Servlets
可以用于實現簡單和小型應用程序的業務邏輯。在 web 框架中,servlets 作為所有傳入請求的入口點(即 controller
servlet);因此,所有流行框架都是在原始的 servlets 上建立的。Servlet 3.0 中的新增特性旨簡化 servlet
應用程序的開發,并讓 servlet
開發人員和框架開發人員從中受益。在以下章節中,我們將詳細介紹每個新增特性,并討論如何使用它們來開發更優秀的應用程序。
開發的簡易性
開發的簡易性是任何技術成功的關鍵因素。Servlet 3.0 API 通過使用 JSR 175 注釋
集中解決開發簡易性問題,允許開發人員采用聲明式的編程方式。這意味著您可以通過使用像 @Servlet 或者 @ServletFilter
這樣的適當注釋對類進行注釋來快速開發一個 servlet 或者過濾器類。注釋不僅使
servlet、過濾器和偵聽器類的編碼更容易,而且,即使應用程序存檔可能有 servlet、過濾器或者上下文偵聽器類也可以選擇用于 web
應用程序的開發部署描述符。Web 容器負責處理各種注釋,其位置在 WEB-INF/classes 目錄下的各個類中、WEB-INF/lib
目錄下的 .jar 文件中、或者應用程序類路徑中任何可以找到的類中。
注釋與部署描述符
值得注意的是,部署描述符優先于注釋。換句話說,部署描述符覆蓋通過注釋機制所規定的配置信
息。Web 部署描述符的 3.0 版本在 web-app 元素上包含一種名為 metadata-complete 的新屬性。該屬性定義了
web 描述符是否完整,或者 web 應用程序的類文件是否針對指定部署信息的注釋而進行檢查。如果該屬性被設置為
true,則部署工具必須忽略類文件中所存在的任何 servlet
注釋,并只使用描述符中所提及的配置細節。否則,如果沒有指定該值或者該值被設置為
false,容器必須針對注釋而掃描應用程序的所有類文件。這個屬性提供了在應用程序啟動階段啟用或者禁用注釋掃描以及對注釋的處理。
在 Servlet 3.0 中所引入的所有注釋都可以在 javax.servlet.http.annotation 和
javax.servlet.http.annotation.jaxrs 軟件包中找到。以下章節闡述 Servlet 3.0 中注釋的完整集合:
@Servlet:javax.servlet.http.annotation.Servlet
是一個類級別的注釋,確認經過注釋的類為一個 servlet 并保存關于所聲明的 servlet 的元數據。urlMappings 屬性是指定
URL 模式(調用該 servlet)的 @Servlet 的強制屬性。當接收到了一個請求時,容器將請求中的 URL 與 servlet 的
urlMappings 進行匹配,且如果 URL 模式匹配,則調用相應的 servlet
以響應該項請求。該注釋的所有其他屬性都是可選的,并帶有合理的默認值。Servlet 類中必須有一種使用像 GET、PUT、POST、HEAD
或者 DELETE 這樣的 HttpMethod 注釋進行注釋的方法。這些方法應將 HttpServletRequest 和
HttpServletResponse 作為方法參數。與以前的版本相反,servlets 3.0 的版本可以作為簡單傳統 Java
對象(Plain Old Java Objects,POJOs)而實現;也就是 servlets 不必再擴展像 HTTPServlet 或者
GenericServlet 這樣的基礎 servlet 實現類。
為了進行比較,在此給出了使用傳統 Servlet 2.5 API 編寫的 Java servlet 代碼片段,如下所示。在 Servlet 2.5 中,只要在部署描述符中配置了 servlet 的詳細信息,web 容器就將初始化 servlet。
- public class MyServlet extends HttpServlet {
- public void doGet (HttpServletRequest req,
- HttpServletResponse res) {
- ....
- }
- }
Deployment descriptor (web.xml)
- <web-app>
- <servlet>
- <servlet-name>MyServlet</servlet-name>
- <servlet-class>samples.MyServlet</servlet-class>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>MyServlet</servlet-name>
- <url-pattern>/MyApp</url-pattern>
- </servlet-mapping>
- ...
-
- </web-app>
這里給出的是使用 Servlet 3.0 API 編寫的較為簡化的版本。當 MyServlet 使用 @Servlet 注釋而被注釋為一個 servlet 時,則在 web 容器的啟動期間對其初始化。注意,在這種情況下部署描述符是可選的。
- @Servlet(urlMappings={"/MyApp"})
- public class MyServlet {
- @GET
- public void handleGet(HttpServletRequest req,
- HttpServletResponse res) {
- ....
- }
- }
Deployment descriptor (web.xml)
optional
@ServletFilter 和 @FilterMapping:您可以使用
javax.servlet.http.annotation.ServletFilter 注釋來注釋過濾器類,從而輕松創建一個 servlet
過濾器。該注釋封裝正被聲明的過濾器的有關元數據。在過濾器類上具有 @FilterMapping 注釋也是強制性的。@FilterMapping
注釋定義用于過濾器的 URL 模式。@ServletFilter 的所有其他屬性都是可選的,并帶有合理的默認值。V3.0 過濾器類現在類似
POJO 類,并且沒有用于這些類所需的 Filter 接口或者非參數公用構造器。以下給出了使用 Servlet v2.5 API 的過濾器類的代碼片段:
- public class MyFilter implements Filter {
- public void doFilter(ServletRequest req,
- ServletResponse res,
- FilterChain chain)
- throws IOException, ServletException {
- ......
- }
- }
Deployment descriptor (web.xml)
- <web-app>
- <filter>
- <filter-name>My Filter</filter-name>
- <filter-class>samples.MyFilter</filter-class>
- </filter>
-
- <filter-mapping>
- <filter-name>My Filter</filter-name>
- <url-pattern>/foo</url-pattern>
- </filter-mapping>
- ...
- </web-app>
使用 Servlet 3.0 編寫的一個示例過濾器類如下所示。因為該類使用 ServletFilter 注釋,所以容器將
MyFilter 標記為一個過濾器類。MyFilter 截取所有收到的請求,其中該請求的 URL 匹配模式 /foo。Servlet 3.0
為過濾器配置提供了可選的部署描述符。
- @ServletFilter
- @FilterMapping("/foo")
- public class MyFilter {
- public void doFilter(HttpServletRequest req,
- HttpServletResponse res) {
- .....
- }
- }
@InitParam:該注釋可以用來定義必須傳遞給 servlet 或者過濾器類的任意初始化參數。它是 @Servlet 和
@ServletFilter 注釋的一個屬性。以下代碼示例解釋了如何將具有 english 值、稱作 lang 的初始化參數傳遞給一個
servlet 類。
- @Servlet(urlMappings={"/MyApp"}, initParams ={@InitParam(name="lang", value="english")})
- public class MyServlet {
- @GET
- public void handleGet(HttpServletRequest req,
- HttpServletResponse res) {
- ....
- }
- }
@ServletContextListener:javax.servlet.http.annotation.ServletContextListener
注釋將該類聲明為一個 servlet 上下文偵聽器。當 web 容器創建或者銷毀 ServletContext
時,該上下文偵聽器接收注釋。上下文偵聽器是一個 POJO 類,且不必實現 ServletContextListener 接口。使用
Servlet 2.5 API 編寫的偵聽器類如下所示。當且僅當您在部署描述符中配置了該偵聽器類,容器才識別它。
- public class MyListener implements ServletContextListener {
- public void contextInitialized(ServletContextEvent sce) {
-
- }
- .....
- }
Deployment Descriptor (web.xml)
- <web-app>
- <listener>
- <listener-class>samples.MyListener</listener-class>
- </listener>
- ....
- </web-app>
使用 Servlet 3.0 API 編寫的一個得到極大簡化的偵聽器類,如下所示。
- @ServletContextListener
- public class MyListener {
- public void contextInitialized (ServletContextEvent sce) {
-
- }
- .....
- }
Deployment Descriptor (web.xml)
optional