Servlet規范簡介——web框架是如何注入到Servlet中的


Servlet規范簡介——web框架是如何注入到Servlet中的

引言

Web框架一般是通過一個Servlet提供統一的請求入口,將指定的資源映射到這個servlet,在這個servlet中進行框架的初始化配置,訪問Web頁面中的數據,進行邏輯處理后,將結果數據與的表現層相融合並展現給用戶。WEB框架想要在符合Servlet規范的容器中運行,同樣也要符合Servlet規范。

將一個WEB框架注入到一個servlet中,主要涉及到Servlet規范中以下部分:

Ø         部署描述符

Ø         映射請求到Servlet

Ø         Servlet生存周期

Ø         請求分發

 Servlet相關技術規范簡介

部署描述符

部署描述符就是位於WEB應用程序的/WEB-INF目錄下的web.xml的XML文件,是WEB應用程序不可分割的部分,管理着WEB應用程序的配置。部署描述符在應用程序開發人員,應用程序組裝人員,應用程序部署人員之間傳遞WEB應用程序的元素和配置信息。

在WEB應用程序的部署描描述符中以下類型的配置和部署信息是所有的servlet容器必須支持的:

Ø         ServletContext初始化參數

Ø         Session配置

Ø        Servlet聲明

Ø        Servlet映射

Ø        應用程序生存周期監聽器

Ø         Filter的定義和映射

Ø         MIME類型的映射

Ø        歡迎文件列表

Ø        錯誤文件列表

出現在部署描述符中的安全信息可以不被支持,除非這個Servlet容器是J2EE規范實現的一部分。

所有正確的WEB應用程序部署描述符(Servlet2.3規范)必須包含下面的DOCTYPE聲明:

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web

Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

 

下面說明在部署描述符中是如何進行Servlet聲明和映射的,這個DTD的全部內容可以在下面這個地址獲得:

http://java.sun.com/dtd/web-app_2_3.dtd

在這個DTD中有關Servlet聲明和映射和映射的部分如下:

<!--

The servlet element contains the declarative data of a

servlet. If a jsp-file is specified and the load-on-startup element

is present, then the JSP should be precompiled and loaded.

Used in: web-app

-->

<!ELEMENT servlet (icon?, servlet-name, display-name?, description?,

(servlet-class|jsp-file), init-param*, load-on-startup?, runas?,

security-role-ref*)>

<!--

The servlet-class element contains the fully qualified class name

of the servlet.

Used in: servlet

-->

<!ELEMENT servlet-class (#PCDATA)>

<!--

The servlet-mapping element defines a mapping between a servlet

and a url pattern

Used in: web-app

-->

<!ELEMENT servlet-mapping (servlet-name, url-pattern)>

<!--

The servlet-name element contains the canonical name of the

servlet. Each servlet name is unique within the web application.

Used in: filter-mapping, servlet, servlet-mapping

-->

<!ELEMENT servlet-name (#PCDATA)>

根據以上DTD,一個典型的Servlet的聲明的格式如下:

<servlet>

<servlet-name>catalog</servlet-name>

<servlet-class>com.mycorp.CatalogServlet</servlet-class>

<init-param>

<param-name>catalog</param-name>

<param-value>Spring</param-value>

</init-param>

</servlet>

一個典型的Servlet映射如下:

<servlet-mapping>

<servlet-name>catalog</servlet-name>

<url-pattern>/catalog/*</url-pattern>

</servlet-mapping>

 

通過上面的方法,我們就聲明了一個名稱為catalog的Servlet,它的實現類為com.mycorp.CatalogServlet,並且帶有一個catalog參數,參數值為Spring,所有向/catalog/*的請求都被映射到名稱為catalog的Servlet。

 

映射請求到Servlet

接收到一個請求后,WEB容器要確定轉到哪一個WEB應用程序。被選擇的應用程序的最長的上下文路徑必須和請求的URL開始部分匹配。URL匹配的部分是映射到Servlet的上下文路徑。

WEB容器下一步必須按照下面的程序定位處理請求的Servlet。

用來映射到Servlet的路徑是請求對象的URL減去上下文的路徑。下面的URL路徑映射規則按順序執行,容器選擇第一個成功的匹配並且不在進行下一個匹配:

Ø        容器試着對請求的路徑和Servlet的路徑進行精確匹配,如果匹配成功則選擇這個Servlet。

Ø        容器會循環的去試着匹配最長的路徑前綴:把’/’當作路徑分隔符,按照路徑樹逐級遞減的完成,選擇最長匹配的Servlet。

Ø        如果這個URL路徑的最后有擴展名(比如.jsp),Servlet容器會試着匹配處理這個擴展名的Servlet。

Ø        如果前面的沒有與前面三條規則相匹配的Servlet,容器會試着為資源請求提供適當的資源,如果有“默認”的Servlet定義給這個應用程序,那么這個Servlet會被使用。

 

容器必須使用一個大小寫敏感的匹配方式。

在部署描述符中,用下面的語法定義映射:

Ø        一個以’/’開始並且以’/*’結束的字符串用來映射路徑。

Ø        一個以’*.’為前綴的字符串用來映射擴展名。

Ø        一個只包含’/’的字符串指示着這個應用程序“默認”的Servlet,在這種情況下,servlet的路徑是請求的URI減去上下文路徑,並且這個路徑是null。

Ø        所有其他的字符只用來精確匹配。

如果容器內置JSP容器,那么*.jsp被映射到這個容器,並允許JSP頁面在需要的時候被執行。這種映射叫做隱含映射。如果WEB應用程序中定義了*.jsp的映射,那么這個映射有比隱含映射高的優先級。

WEB容器允許顯式的聲明隱含映射以獲得優先級,例如,*.shtml的隱含映射可以在服務器上被映射為包含功能。

映射實例:

path pattern

servlet

/foo/bar/*

servlet1

/baz/*

servlet2

/catalog

servlet3

*.bop

servlet4

下面是實際請求映射的結果

incoming path

servlet handling request

/foo/bar/index.html

servlet1

/foo/bar/index.bop

servlet1

/baz

servlet2

/baz/index.html

servlet2

/catalog

servlet3

/catalog/index.html

“default” servlet

/catalog/racecar.bop

servlet4

/index.bop

servlet4

請注意/catalog/index.html 和/catalog/racecar.bop這兩種情況,因為是精確匹配,所以並沒有映射到處理/catalog的servlet。

 

Servlet生存周期

在介紹Servlet的生存周期之前需要先介紹一下javax.servlet.Servlet接口。所有的Servlet必須實現或者間接實現這個借口,我們通常可以通過繼承javax.servlet.GenericServlet或者javax.servlet.http.HttpServlet.類來實現這個接口。

這個接口中定義了下面5種方法:

public void init(ServletConfig config);

public ServletConfig getServletConfig();

public void service(ServletRequest req, ServletResponse res);

public String getServletInfo();

public void destroy() ;

 

init()方法

init方法在容器器裝入Servlet 時執行,Servlet容器在實例化后只調用一次init方法, init方法必須在servlet接收到任何請求之前完成。

這個方法通常用來進行一些資源的管理和初始化,如從配置文件讀取配置數據,讀取初始化參數,初始化緩沖遲等一次性的操作。

getServletConfig()方法

GetServletConfig方法返回一個 ServletConfig 對象,該對象用來返回這個Servlet的初始化信息和啟動參數。返回的是傳遞到init方法ServletConfig。

Service()方法

Service方法是應用程序邏輯的進入點,是servlet方法的核心,WEB容器調用這個方法來響應進入的請求,只有servlet成功被init()方法初始化后,Service方法才會被調用。

getServletInfo()方法

這個方法返回一個字符串對象,提供有關servlet 的信息,如作者、版本等。

destroy()方法

destroy方法在容器移除Servlet 時執行,同樣只執行一次。這個方法會在所有的線程的service()方法執行完成或者超時后執行,調用這個方法后,容器不會再調用這個servlet的方法,也就是說容器不再把請求發送給這個Servlet。 這個方法給servlet釋放占用的資源的機會,通常用來執行一些清理任務。

 

這個接口定義了初始化一個servlet,服務請求和從容器中移除servlet的方法。他們按照下面的順序執行:

1.         servlet被實例化后,用init方法進行初始化

2.         客戶端的任何請求都調用service方法

3.         servlet被移除服務,調用destroy方法銷毀

servlet的生存周期如下圖:
 

請求分發

請求分發可以讓一個Servlet把請求分配到另外一個資源,RequestDispatcher接口提供了實現他的機制。可以通過下面兩種方式從ServletContext中獲得一個實現了RequestDispatcher接口的對象:

• getRequestDispatcher

• getNamedDispatcher

getRequestDispatcher方法接受一個指向目標資源的URL路徑

RequestDispatcher rd = getServletContext().getRequestDispatcher(“/catalog”);

 

 

getNamedDispatcher方法接受一個Servlet名稱參數,這個名稱是在部署描述符中<servlet-name>元素指定的那個名稱。

RequestDispatcher rd = getServletContext().getNamedDispatcher (“catalog”);

 

 

RequestDispatcher接口有兩個方法,允許你在調用的servlet完成初步處理后把請求響應分配到另外一個資源,

forward()方法:

public void forward(ServletRequest request, ServletReponse reponse) throws SwerletException,IOException

forward方法上讓你把請求轉發到另外的Servlet或者jsp或者html等資源,由這個資源接下來負責響應。如:

RequestDispatcher rd = getServletContext().getRequestDispatcher(“/catalog”);

rd. forward(request,response);

 

include()方法:

public void include (ServletRequest request, ServletReponse reponse) throws SwerletException,IOException

include方法讓你的Servlet響應中包含另外一個資源生成內容

RequestDispatcher rd = getServletContext().getRequestDispatcher(“/catalog”);

rd. include(request,response);

 

 

結合WebWork的具體分析

WebWork是由OpenSymphony組織開發實現MVC模式的J2EE Web框架。在介紹完servlet規范的相關內容后,我們看看WebWork是如何注入到一個Servlet中的,假設我們有一個上下文環境為“/WebWorkdDemo”的WEB應用。

部署描述符

在部署描述符中,我們需要進行如下配置:

<servlet>

<servlet-name>webwork</servlet-name>

<servlet-class>com.opensymphony.webwork.dispatcher.ServletDispatcher</servlet-class>

</servlet>

……

<servlet-mapping>

<servlet-name>webwork</servlet-name>

<url-pattern>*.action</url-pattern>

</servlet-mapping>

我們聲明了一個名為webwork的Servlet和*.action到這個Servlet的映射,這個Servlet就是webwork中的controller,擔任MVC框架中非常重要的控制器角色。

映射請求到Servlet

在XWork的配置文件xwork.xml中有如下片段:

<action name="demo" class=" webworkapp.DemoAction">

<result name="success" type="dispatcher">

<param name="location">/demo.jsp</param>

</result>

</action>

這樣我們由http://localhost:8080/WebWorkDemo/demo.action這個URL向服務器發出請求時,WEB容器首先確定轉到哪一個WEB應用程序,容器將請求URL和上下文環境進行匹配后知道將轉到/WebWorkdDemo這個WEB應用。

接下來容器會在/WebWorkdDemo這個應用的部署描述符中進行查找處理這個請求的servlet,根據后綴*.action找到名稱為webwork這個Servlet,這樣根據部署描述符,這個請求被映射到webwork中的controller組 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM