寫了好多小項(xiàng)目后也沒弄明白<url-pattern>的真正意義,,寫跳轉(zhuǎn)的時(shí)候也是跳的三心二意的,今天查了一下web.xml的詳細(xì)配置,看了看servlet-mapping的講解,,豁然開朗,,做了做小實(shí)驗(yàn),原來是這樣,,捂臉,。下面把看到的文章的servlet片段摘抄過來,先附上鏈接(http://blog.csdn.net/believejava/article/details/43229361)(作者如有意見,,私信刪文),;
容器的Context對象對請求路徑(URL)做出處理,去掉請求URL的上下文路徑后,,按路徑映射規(guī)則和Servlet映射路徑(<url-
pattern>)做匹配,,如果匹配成功,則調(diào)用這個(gè)Servlet處理請求,。
servlet容器對url的匹配過程:
當(dāng)一個(gè)請求發(fā)送到servlet容器的時(shí)候,,容器先會(huì)將請求的url減去當(dāng)前應(yīng)用上下文的路徑作為servlet的映射url,比如我訪問的是http://localhost/test/aaa.html,,我的應(yīng)用上下文是test,,容器會(huì)將http://localhost/test去掉,剩下的/aaa.html部分拿來做servlet的映射匹配,。這個(gè)映射匹配過程是有順序的,,而且當(dāng)有一個(gè)servlet匹配成功以后,就不會(huì)去理會(huì)剩下的servlet了(filter不同,,后文會(huì)提到),。其匹配規(guī)則和順序如下:
1. 精確路徑匹配。例子:比如servletA 的url-pattern為 /test,,servletB的url-pattern為 /* ,,這個(gè)時(shí)候,如果我訪問的url為http://localhost/test ,,這個(gè)時(shí)候容器就會(huì)先進(jìn)行精確路徑匹配,,發(fā)現(xiàn)/test正好被servletA精確匹配,那么就去調(diào)用servletA,,也不會(huì)去理會(huì)其他的servlet了,。
2. 最長路徑匹配。例子:servletA的url-pattern為/test/*,,而servletB的url-pattern為/test/a/*,,此時(shí)訪問http://localhost/test/a時(shí),容器會(huì)選擇路徑最長的servlet來匹配,,也就是這里的servletB,。
3. 擴(kuò)展匹配,,如果url最后一段包含擴(kuò)展,容器將會(huì)根據(jù)擴(kuò)展選擇合適的servlet,。例子:servletA的url-pattern:*.action
4. 如果前面三條規(guī)則都沒有找到一個(gè)servlet,,容器會(huì)根據(jù)url選擇對應(yīng)的請求資源。如果應(yīng)用定義了一個(gè)default servlet,,則容器會(huì)將請求丟給default servlet(什么是default servlet,?后面會(huì)講)。
根據(jù)這個(gè)規(guī)則表,,就能很清楚的知道servlet的匹配過程,所以定義servlet的時(shí)候也要考慮url-pattern的寫法,,以免出錯(cuò),。
對于filter,不會(huì)像servlet那樣只匹配一個(gè)servlet,,因?yàn)閒ilter的集合是一個(gè)鏈,,所以只會(huì)有處理的順序不同,而不會(huì)出現(xiàn)只選擇一個(gè)filter,。Filter的處理順序和filter-mapping在web.xml中定義的順序相同,。
<servlet></servlet>
- <!--****************************servlet配置******************************-->
- <!-- Spring view分發(fā)器 對所有的請求都由business對應(yīng)的類來控制轉(zhuǎn)發(fā) -->
- <servlet>
- <servlet-name>business</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>publishContext</param-name>
- <param-value>false</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <!-- 用戶登出 -->
- <servlet>
- <servlet-name>LogOutServlet</servlet-name>
- <servlet-class>com.yonyou.mcloud.cas.web.servlet.LogOutServlet</servlet-class>
- <init-param>
- <param-name>serverLogoutUrl</param-name>
- <param-value>https://dev.:443/sso-server/logout</param-value>
- </init-param>
- <init-param>
- <param-name>serverName</param-name>
- <param-value>http://10.1.215.40:80/business/</param-value>
- </init-param>
- </servlet>
- <!--****************************servlet映射關(guān)系配置*************************-->
- <servlet-mapping>
- <servlet-name>LogOutServlet</servlet-name>
- <url-pattern>/logout</url-pattern>
- </servlet-mapping>
- <servlet-mapping>
- <servlet-name>business</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- Servlet介紹:
Servlet通常稱為服務(wù)器端小程序,是運(yùn)行在服務(wù)器端的程序,,用于處理及響應(yīng)客戶的請求,。Servlet是個(gè)特殊的java類,繼承于HttpServlet,??蛻舳送ǔV挥?/span>GET和POST兩種請求方式,Servlet為了響應(yīng)則兩種請求,,必須重寫doGet()和doPost()方法,。大部分時(shí)候,Servlet對于所有的請求響應(yīng)都是完全一樣的,,此時(shí)只需要重寫service()方法即可響應(yīng)客戶端的所有請求,。
另外HttpServlet有兩個(gè)方法
- init(ServletConfig config):創(chuàng)建Servlet實(shí)例時(shí),調(diào)用該方法的初始化Servlet資源,。
- destroy():銷毀Servlet實(shí)例時(shí),,自動(dòng)調(diào)用該方法的回收資源。
通常無需重寫init()和destroy()兩個(gè)方法,,除非需要在初始化Servlet時(shí),,完成某些資源初始化的方法,才考慮重寫init()方法,,如果重寫了init()方法,,應(yīng)在重寫該方法的第一行調(diào)用super.init(config),,該方法將調(diào)用HttpServlet的init()方法。如果需要在銷毀Servlet之前,,先完成某些資源的回收,,比如關(guān)閉數(shù)據(jù)庫連接,才需要重寫destory方法(),。
Servlet的生命周期:
創(chuàng)建Servlet實(shí)例有兩個(gè)時(shí)機(jī):
- 客戶端第一次請求某個(gè)Servlet時(shí),,系統(tǒng)創(chuàng)建該Servlet的實(shí)例,大部分Servlet都是這種Servlet,。
- Web應(yīng)用啟動(dòng)時(shí)立即創(chuàng)建Servlet實(shí)例,,即load-on-start
Servlet。
每個(gè)Servlet的運(yùn)行都遵循如下生命周期:
- 創(chuàng)建Servlet實(shí)例,。
- Web容器調(diào)用Servlet的init()方法,,對Servlet進(jìn)行初始化。
- Servlet初始化后,,將一直存在于容器中,,用于響應(yīng)客戶端請求,如果客戶端發(fā)送GET請求,,容器調(diào)用Servlet的doGet()方法處理并響應(yīng)請求,;如果客戶端發(fā)送POST請求,容器調(diào)用Servlet的doPost()方法處理并響應(yīng)請求,?;蛘呓y(tǒng)一使用service()方法處理來響應(yīng)用戶請求。
- Web容器決定銷毀Servlet時(shí),,先調(diào)用Servlet的destory()方法,,通常在關(guān)閉Web應(yīng)用時(shí)銷毀Servlet實(shí)例。
- Servlet配置:
為了讓Servlet能響應(yīng)用戶請求,,還必須將Servlet配置在web應(yīng)用中,,配置Servlet需要修改web.xml文件。
從Servlet3.0開始,,配置Servlet有兩種方式:
- 在Servlet類中使用@WebServlet Annotation進(jìn)行配置,。
- 在web.xml文件中進(jìn)行配置。
我們用web.xml文件來配置Servlet,,需要配置<servlet>和<servlet-mapping>,。
<servlet>用來聲明一個(gè)Servlet。<icon>,、<display-name>和<description>元素的用法和<filter>的用法相同,。<init-param>元素與<context-param>元素具有相同的元素描述符,可以使用<init-param>子元素將初始化參數(shù)名和參數(shù)值傳遞給Servlet,,訪問Servlet配置參數(shù)通過ServletConfig對象來完成,,ServletConfig提供如下方法:
java.lang.String.getInitParameter(java.lang.String name):用于獲取初始化參數(shù)
ServletConfig獲取配置參數(shù)的方法和ServletContext獲取配置參數(shù)的方法完全一樣,,只是ServletConfig是取得當(dāng)前Servlet的配置參數(shù),而ServletContext是獲取整個(gè)Web應(yīng)用的配置參數(shù),。
- <description>,、<display-name>和<icon>
- <description>:為Servlet指定一個(gè)文本描述。
- <display-name>:為Servlet提供一個(gè)簡短的名字被某些工具顯示,。
- <icon>:為Servlet指定一個(gè)圖標(biāo),,在圖形管理工具中表示該Servlet。
- <servlet-name>,、<servlet-class>和<jsp-file>元素
<servlet>必須含有<servlet-name>和<servlet-class>,,或者<servlet-name>和<jsp-file>。 描述如下:
- <servlet-name>用來定義servlet的名稱,,該名稱在整個(gè)應(yīng)用中必須是惟一的
- <servlet-class>用來指定servlet的完全限定的名稱,。
- <jsp-file>用來指定應(yīng)用中JSP文件的完整路徑。這個(gè)完整路徑必須由/開始,。
- <load-on-startup>
如果load-on-startup元素存在,而且也指定了jsp-file元素,,則JSP文件會(huì)被重新編譯成Servlet,,同時(shí)產(chǎn)生的Servlet也被載入內(nèi)存。<load-on-startup>的內(nèi)容可以為空,,或者是一個(gè)整數(shù),。這個(gè)值表示由Web容器載入內(nèi)存的順序。
舉個(gè)例子:如果有兩個(gè)Servlet元素都含有<load-on-startup>子元素,,則<load-on-startup>子元素值較小的Servlet將先被加載,。如果<load-on-startup>子元素值為空或負(fù)值,則由Web容器決定什么時(shí)候加載Servlet,。如果兩個(gè)Servlet的<load-on-startup>子元素值相同,,則由Web容器決定先加載哪一個(gè)Servlet。
<load-on-startup>1</load-on-startup>表示啟動(dòng)容器時(shí),,初始化Servlet,。
- <servlet-mapping>
<servlet-mapping>含有<servlet-name>和<url-pattern>
- <servlet-name>:Servlet的名字,唯一性和一致性,,與<servlet>元素中聲明的名字一致,。
- <url-pattern>:指定相對于Servlet的URL的路徑。該路徑相對于web應(yīng)用程序上下文的根路徑,。<servlet-mapping>將URL模式映射到某個(gè)Servlet,,即該Servlet處理的URL。
- 加載Servlet的過程
容器的Context對象對請求路徑(URL)做出處理,,去掉請求URL的上下文路徑后,,按路徑映射規(guī)則和Servlet映射路徑(<url-
pattern>)做匹配,,如果匹配成功,則調(diào)用這個(gè)Servlet處理請求,。
- DispatcherServlet在web.xml中的配置:
- <!-- Spring view分發(fā)器 對所有的請求都由business對應(yīng)的類來控制轉(zhuǎn)發(fā) -->
- <servlet>
- <servlet-name>business</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>publishContext</param-name>
- <param-value>false</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
配置Spring MVC,,指定處理請求的Servlet,有兩種方式:
l 默認(rèn)查找MVC配置文件的地址是:/WEB-INF/${servletName}-servlet.xml
l 可以通過配置修改MVC配置文件的位置,,需要在配置DispatcherServlet時(shí)指定MVC配置文件的位置,。
我們在平臺項(xiàng)目兩個(gè)工程中分別使用了不同的配置方式,介紹如下:
我們在business-client工程中按照默認(rèn)方式查找MVC的配置文件,,配置文件目錄為: /WEB-INF/business-servlet.xml,。工程目錄結(jié)構(gòu)如下所示:
我們在public-base-server工程中,通過第2種方式進(jìn)行配置,,把spring-servlet.xml放到src/main/resources/config/spring-servlet.xml,,則需要在配置DispatcherServlet時(shí)指定<init-param>標(biāo)簽。具體代碼如下:
- <servlet>
- <servlet-name>spring</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>publishContext</param-name>
- <param-value>false</param-value>
- </init-param>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:config/spring-servlet.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
工程目錄結(jié)構(gòu)如下:
其中,,classpath是web項(xiàng)目的類路徑,,可以理解為classes下面。因?yàn)闊o論這些配置文件放在哪,,編譯之后如果沒有特殊情況的話都直接在classes下面,。jar包的話雖然放在lib文件夾里,但實(shí)際上那些類可以直接引用,,比如:com.test.ABC,,仿佛也在classes下面一樣。
在我們的工程里,,經(jīng)過驗(yàn)證,,maven工程這兩個(gè)
路徑經(jīng)過編譯后生成的文件都位于classes目錄下,,即這兩個(gè)路徑相當(dāng)于類路徑,,在下面創(chuàng)建config文件夾(folder),,然后創(chuàng)建自定義的xml配置文件即可,。
classpath和classpath*區(qū)別:
同名資源存在時(shí),,classpath只從第一個(gè)符合條件的classpath中加載資源,而classpath*會(huì)從所有的classpath中加載符合條件的資源,。classpath*,需要遍歷所有的classpath,,效率肯定比不上classpath,,因此在項(xiàng)目設(shè)計(jì)的初期就盡量規(guī)劃好資源文件所在的路徑,,避免使用classpath*來加載,。
- ContextLoaderListener和DispatcherServlet初始化上下文關(guān)系和區(qū)別:
從上圖可以看出,ContextLoaderListener初始化的上下文加載的Bean是對于整個(gè)應(yīng)用程序共享的,一般如:DAO層,、Service層Bean,;DispatcherServlet初始化的上下文加載的Bean是只對Spring MVC有效的Bean,,如:Controller,、HandlerMapping,、HandlerAdapter等,,該初始化上下文只加載Web相關(guān)組件,。
注意:用戶可以配置多個(gè)DispatcherServlet來分別處理不同的url請求,每個(gè)DispatcherServlet上下文都對應(yīng)一個(gè)自己的子Spring容器,他們都擁有相同的父Spring容器(業(yè)務(wù)層,持久(dao)bean所在的容器),。
|