spring是目前最流行的框架。創建java web項目時,我們首先會遇到的配置文件就是web.xml,這是javaweb為我們封裝的邏輯,不在今天的研究中。下面我們將簡單講講web.xml中的配置。
一、一個空的web.xml
1
|
2
3
4
5
6
|
<? xml version = "1.0" encoding = "UTF-8" ?> < web-app version = "3.0" xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " xmlns = " http://java.sun.com/xml/ns/javaee " xmlns:web = " http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd " xsi:schemaLocation = " http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd " id = "WebApp_ID" > </ web-app > |
二、標簽介紹
web.xml中比較常見的標簽以及其加載順序為:
context-param > listener > filter > servlet
1、 <display-name>Archetype Created Web Application</display-name>
display-name 是標識項目的名稱,這個不是很常用,可有可無的,或者說不需要我們去在意的東西。
2、 <context-param>
1
|
2
3
4
|
< context-param > < param-name >webAppRootKey</ param-name > < param-value >60000</ param-value > </ context-param > |
context-param 是web.xml首先加載的標簽,其下子標簽有param-name和param-value.
此所設定的參數,在JSP網頁中可以使用下列方法來取得:
1
|
|
${initParam.webAppRootKey} |
若在Servlet可以使用下列方法來獲得:
String param_name=getServletContext().getInitParamter(“webAppRootKey”);
3、listener
1
|
2
3
|
< listener > < listener-class >org.springframework.web.context.request.RequestContextListener</ listener-class > </ listener > |
listenter在項目開始的時候就注入進來,盡在context-param之后,所以正常我們將spring配置在listener 中,這樣方法spring 初始化相關的bean。
4、filter
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
< filter > < filter-name >CharacterEncodingFilter</ filter-name > < filter-class >org.springframework.web.filter.CharacterEncodingFilter</ filter-class > < init-param > < param-name >encoding</ param-name > < param-value >UTF-8</ param-value > </ init-param > < init-param > < param-name >forceEncoding</ param-name > < param-value >true</ param-value > </ init-param > </ filter > < filter-mapping > < filter-name >CharacterEncodingFilter</ filter-name > < url-pattern >/*</ url-pattern > </ filter-mapping > |
filter起到一個過濾的作用,在servlet執行前后,像上面的配置就是在過濾servlet前將編碼轉換UTF-8,filter-mapping 則是將filter和url路徑進行映射。其中init-param則是將初始化需要的參數傳入到filter-class中從而進行初始化。filter和filter-mapping中的name必須是相同的,才能起到映射的作用,而filter-mapping 中的url-pattern則是匹配請求路徑的。上面‘/*'表示過濾所有請求的servlet,如果寫成‘/zxh',則過濾http://localhost:8080/項目名/zxh這個請求。
5、servlet
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
< servlet > <!-- 配置DispatcherServlet --> < servlet-name >springMvc</ servlet-name > < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > <!-- 指定spring mvc配置文件位置 不指定使用默認情況 --> < init-param > < param-name >contextConfigLocation</ param-name > < param-value >classpath:spring/spring-mvc.xml</ param-value > </ init-param > <!-- 設置啟動順序 --> < load-on-startup >1</ load-on-startup > </ servlet > <!-- ServLet 匹配映射 --> < servlet-mapping > < servlet-name >springMvc</ servlet-name > < url-pattern >*.zxh</ url-pattern > </ servlet-mapping > |
servlet和filter類似,需要先指定servlet對應的class類,然后將這個類和utl路徑請求地址進行映射。這里不多說了。
以上就是web.xml文件中出現最多的幾個標簽。其他的比如:
6、歡迎頁
1
|
2
3
|
< welcome-file-list > < welcome-file >login.jsp</ welcome-file > </ welcome-file-list > |
7、錯誤頁
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<!-- 后臺程序異常錯誤跳轉頁面 --> < error-page > < exception-type >java.lang.Throwable</ exception-type > < location >/views/error.jsp</ location > </ error-page > <!-- 500跳轉頁面--> < error-page > < error-code >500</ error-code > < location >/views/500.jsp</ location > </ error-page > <!-- 404跳轉頁面 --> < error-page > < error-code >404</ error-code > < location >/views/404.jsp</ location > </ error-page > |
三、示例
1、spring 框架解決字符串編碼問題:過濾器 CharacterEncodingFilter(filter-name)
2、在web.xml配置監聽器ContextLoaderListener(listener-class)
ContextLoaderListener的作用就是啟動Web容器時,自動裝配ApplicationContext的配置信息。因為它實現了ServletContextListener這個接口,在web.xml配置這個監聽器,啟動容器時,就會默認執行它實現的方法。
3、部署applicationContext的xml文件:contextConfigLocation(context-param下的param-name)
4、DispatcherServlet是前置控制器,配置在web.xml文件中的。攔截匹配的請求,Servlet攔截匹配規則要自已定義,把攔截下來的請求,依據某某規則分發到目標Controller(我們寫的Action)來處理。
DispatcherServlet(servlet-name、servlet-class、init-param、param-name(contextConfigLocation)、param-value)
在DispatcherServlet的初始化過程中,框架會在web應用的 WEB-INF文件夾下尋找名為[servlet-name]-servlet.xml 的配置文件,生成文件中定義的bean
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
<? xml version = "1.0" encoding = "UTF-8" ?> < web-app version = "3.0" xmlns = " http://java.sun.com/xml/ns/javaee " xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " xsi:schemaLocation = " http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd " > <!-- 在Spring框架中是如何解決從頁面傳來的字符串的編碼問題的呢? 下面我們來看看Spring框架給我們提供過濾器CharacterEncodingFilter 這個過濾器就是針對于每次瀏覽器請求進行過濾的,然后再其之上添加了父類沒有的功能即處理字符編碼。 其中encoding用來設置編碼格式,forceEncoding用來設置是否理會 request.getCharacterEncoding()方法,設置為true則強制覆蓋之前的編碼格式。--> < filter > < filter-name >characterEncodingFilter</ filter-name > < filter-class >org.springframework.web.filter.CharacterEncodingFilter</ filter-class > < init-param > < param-name >encoding</ param-name > < param-value >UTF-8</ param-value > </ init-param > < init-param > < param-name >forceEncoding</ param-name > < param-value >true</ param-value > </ init-param > </ filter > < filter-mapping > < filter-name >characterEncodingFilter</ filter-name > < url-pattern >/*</ url-pattern > </ filter-mapping > <!-- 項目中使用Spring 時,applicationContext.xml配置文件中并沒有BeanFactory,要想在業務層中的class 文件中直接引用Spring容器管理的bean可通過以下方式--> <!--1、在web.xml配置監聽器ContextLoaderListener--> <!--ContextLoaderListener的作用就是啟動Web容器時,自動裝配ApplicationContext的配置信息。因為它實現了ServletContextListener這個接口,在web.xml配置這個監聽器,啟動容器時,就會默認執行它實現的方法。 在ContextLoaderListener中關聯了ContextLoader這個類,所以整個加載配置過程由ContextLoader來完成。 它的API說明 第一段說明ContextLoader可以由 ContextLoaderListener和ContextLoaderServlet生成。 如果查看ContextLoaderServlet的API,可以看到它也關聯了ContextLoader這個類而且它實現了HttpServlet這個接口 第二段,ContextLoader創建的是 XmlWebApplicationContext這樣一個類,它實現的接口是WebApplicationContext->ConfigurableWebApplicationContext->ApplicationContext-> BeanFactory這樣一來spring中的所有bean都由這個類來創建 IUploaddatafileManager uploadmanager = (IUploaddatafileManager) ContextLoaderListener.getCurrentWebApplicationContext().getBean("uploadManager"); --> < listener > < listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class > </ listener > <!--2、部署applicationContext的xml文件--> <!--如果在web.xml中不寫任何參數配置信息,默認的路徑是"/WEB-INF/applicationContext.xml, 在WEB-INF目錄下創建的xml文件的名稱必須是applicationContext.xml。 如果是要自定義文件名可以在web.xml里加入contextConfigLocation這個context參數: 在<param-value> </param-value>里指定相應的xml文件名,如果有多個xml文件,可以寫在一起并以“,”號分隔。 也可以這樣applicationContext-*.xml采用通配符,比如這那個目錄下有applicationContext-ibatis-base.xml, applicationContext-action.xml,applicationContext-ibatis-dao.xml等文件,都會一同被載入。 在ContextLoaderListener中關聯了ContextLoader這個類,所以整個加載配置過程由ContextLoader來完成。--> < context-param > < param-name >contextConfigLocation</ param-name > < param-value >classpath:spring/applicationContext.xml</ param-value > </ context-param > <!--如果你的DispatcherServlet攔截"/",為了實現REST風格,攔截了所有的請求,那么同時對*.js,*.jpg等靜態文件的訪問也就被攔截了。--> <!--方案一:激活Tomcat的defaultServlet來處理靜態文件--> <!--要寫在DispatcherServlet的前面, 讓 defaultServlet先攔截請求,這樣請求就不會進入Spring了,我想性能是最好的吧。--> < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.css</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.swf</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.gif</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.jpg</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.png</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.js</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.html</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.xml</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.json</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >default</ servlet-name > < url-pattern >*.map</ url-pattern > </ servlet-mapping > <!--使用Spring MVC,配置DispatcherServlet是第一步。DispatcherServlet是一個Servlet,,所以可以配置多個DispatcherServlet--> <!--DispatcherServlet是前置控制器,配置在web.xml文件中的。攔截匹配的請求,Servlet攔截匹配規則要自已定義,把攔截下來的請求,依據某某規則分發到目標Controller(我們寫的Action)來處理。--> < servlet > < servlet-name >DispatcherServlet</ servlet-name > <!--在DispatcherServlet的初始化過程中,框架會在web應用的 WEB-INF文件夾下尋找名為[servlet-name]-servlet.xml 的配置文件,生成文件中定義的bean。--> < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > <!--指明了配置文件的文件名,不使用默認配置文件名,而使用dispatcher-servlet.xml配置文件。--> < init-param > < param-name >contextConfigLocation</ param-name > <!--其中<param-value>**.xml</param-value> 這里可以使用多種寫法--> <!--1、不寫,使用默認值:/WEB-INF/<servlet-name>-servlet.xml--> <!--2、<param-value>/WEB-INF/classes/dispatcher-servlet.xml</param-value>--> <!--3、<param-value>classpath*:dispatcher-servlet.xml</param-value>--> <!--4、多個值用逗號分隔--> < param-value >classpath:spring/dispatcher-servlet.xml</ param-value > </ init-param > < load-on-startup >1</ load-on-startup > <!--是啟動順序,讓這個Servlet隨Servletp容器一起啟動。--> </ servlet > < servlet-mapping > <!--這個Servlet的名字是dispatcher,可以有多個DispatcherServlet,是通過名字來區分的。每一個DispatcherServlet有自己的WebApplicationContext上下文對象。同時保存的ServletContext中和Request對象中.--> <!--ApplicationContext是Spring的核心,Context我們通常解釋為上下文環境,我想用“容器”來表述它更容易理解一些,ApplicationContext則是“應用的容器”了:P,Spring把Bean放在這個容器中,在需要的時候,用getBean方法取出--> < servlet-name >DispatcherServlet</ servlet-name > <!--Servlet攔截匹配規則可以自已定義,當映射為@RequestMapping("/user/add")時,為例,攔截哪種URL合適?--> <!--1、攔截*.do、*.htm, 例如:/user/add.do,這是最傳統的方式,最簡單也最實用。不會導致靜態文件(jpg,js,css)被攔截。--> <!--2、攔截/,例如:/user/add,可以實現現在很流行的REST風格。很多互聯網類型的應用很喜歡這種風格的URL。弊端:會導致靜態文件(jpg,js,css)被攔截后不能正常顯示。 --> < url-pattern >/</ url-pattern > <!--會攔截URL中帶“/”的請求。--> </ servlet-mapping > < welcome-file-list > <!--指定歡迎頁面--> < welcome-file >login.html</ welcome-file > </ welcome-file-list > < error-page > <!--當系統出現404錯誤,跳轉到頁面nopage.html--> < error-code >404</ error-code > < location >/nopage.html</ location > </ error-page > < error-page > <!--當系統出現java.lang.NullPointerException,跳轉到頁面error.html--> < exception-type >java.lang.NullPointerException</ exception-type > < location >/error.html</ location > </ error-page > < session-config > <!--會話超時配置,單位分鐘--> < session-timeout >360</ session-timeout > </ session-config > </ web-app > |
四、spring加載
通過上面的了解,我們可以看出spring核心配置文件就是listener那塊。在監聽之前我們已經通過context-param將spring配置文件傳到上下文中了(application)。下面我們就來看看spring是如何工作的吧
第一步:
點開listener源碼,我們發現他有下面幾個方法。和繼承的關系。我們發現他實現了ContextLoaderListener這個接口,這個接口在參數設置好之后自動執行contextInitialized方法的。
那么我們來看看contextInitialized方法
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null ) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!" ); } Log logger = LogFactory.getLog(ContextLoader. class ); servletContext.log( "Initializing Spring root WebApplicationContext" ); if (logger.isInfoEnabled()) { logger.info( "Root WebApplicationContext: initialization started" ); } long startTime = System.currentTimeMillis(); try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if ( this .context == null ) { this .context = createWebApplicationContext(servletContext); } if ( this .context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this .context; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null ) { // The context instance was injected without an explicit parent -> // determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } configureAndRefreshWebApplicationContext(cwac, servletContext); } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this .context); ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if (ccl == ContextLoader. class .getClassLoader()) { currentContext = this .context; } else if (ccl != null ) { currentContextPerThread.put(ccl, this .context); } if (logger.isDebugEnabled()) { logger.debug( "Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]" ); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info( "Root WebApplicationContext: initialization completed in " + elapsedTime + " ms" ); } return this .context; } catch (RuntimeException ex) { logger.error( "Context initialization failed" , ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error( "Context initialization failed" , err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } } |
仔細研究官方解釋,就是在這里初始化application,這里會用到contextClass+contextConfigLocation兩個參數,如果contextClass在context-param提供了,我們就會根據這一個class去初始化application,很顯然我們正常配置都沒有配這個,而是配置了后者,配置了后者就會去根據contextConfigLocation中提供的配置文件去解析然后創建相關的bean和application操作,這個方法的最后會執行configureAndRefreshWebApplicationContext方法。這個方法就是在根據contextConfigLocation提供的配置文件中創建相關的bean。
五、springMVC 加載
springMVC其實和spring是一樣的,但是他不用再程序開始時訪問
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
< servlet > <!-- 配置DispatcherServlet --> < servlet-name >springMvc</ servlet-name > < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > <!-- 指定spring mvc配置文件位置 不指定使用默認情況 --> < init-param > < param-name >contextConfigLocation</ param-name > < param-value >classpath:spring/spring-mvc.xml</ param-value > </ init-param > <!-- 設置啟動順序 --> < load-on-startup >1</ load-on-startup > </ servlet > <!-- ServLet 匹配映射 --> < servlet-mapping > < servlet-name >springMvc</ servlet-name > < url-pattern >*.zxh</ url-pattern > </ servlet-mapping > |
看DispatcherServlet源碼中對contextConfigLocation參數的解釋
上面明確指出我們這個參數給XmlWebApplicationContext類的,我們在進入XmlWebApplicationContext類看看究竟。
這樣我們很容易理解為什么springmvc默認的配置文件會在WEB-INF/application.xml中的吧。
在dispatcherservlet中有一個初始化方法,這里就初始化配置中一些東西,比如說文件上傳適配器的配置等等。
1
|
2
3
4
5
6
7
8
9
10
11
|
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } |
總結
spring+springmvc在配置中主要就是上面的兩個配置,當然spring的強大不是我們一兩天能夠研究來的,我上面只是簡單的研究討論了一下。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/liuqz2009/article/details/72833678