spring web.xml 難點配置總結【轉】
web.xml
web.xml是所有web專案的根源,沒有它,任何web專案都啟動不了,所以有必要了解相關的配置.
ContextLoderListener,ContextLoaderServlet,DispatcherServlet 區別
web.xml中可以有三種方式來配置xml去載入Bean:
org.springframework.web.context.ContextLoaderListener org.springframework.web.context.ContextLoaderServlet org.springframework.web.servlet.DispatcherServlet
- ContextLoaderListener 和 ContextLoaderServlet : 本質上是等同的,都是呼叫ContextLoader來載入web程式的上下文,載入完成以後,都是在ServletContext中,只不過listener需要Servlet2.3及以上支援。
- ContextLoaderListene與DispatcherServlet : 用DispatcherServlet載入的Bean是隸屬於此Servlet的(所以spring可以配置多個分別擁有各自環境的DispatcherServlet),因此其他servlet無法獲取到該Context。這一現象在buffalo配置時曾經出現(無法找到服務bean)。分析了buffalo和spring的原始碼後,將xml在ContextLoaderListener配置才得以解決。 所以web.xml檔案中若只使用了一個dispatcherservlet來進行分發,則使用dispatcherservlet contextloaderlistener 來載入bean例項是等效的。
各元素初始化過程
初始化過程:
- 在啟動Web專案時,容器(比如Tomcat)會讀web.xml配置檔案中的兩個節點<listener>和<contex-param>。
- 接著容器會建立一個ServletContext(上下文),應用範圍內即整個WEB專案都能使用這個上下文。
- 接著容器會將讀取到<context-param>轉化為鍵值對,並交給ServletContext。
- 容器建立<listener></listener>中的類例項,即建立監聽(備註:listener定義的類可以是自定義的類但必須需要繼承ServletContextListener)。
- 在監聽的類中會有一個contextInitialized(ServletContextEvent event)初始化方法,在這個方法中可以通過event.getServletContext().getInitParameter("contextConfigLocation") 來得到context-param 設定的值。在這個類中還必須有一個contextDestroyed(ServletContextEvent event) 銷燬方法.用於關閉應用前釋放資源,比如說資料庫連線的關閉。
- 得到這個context-param的值之後,你就可以做一些操作了.注意,這個時候你的WEB專案還沒有完全啟動完成.這個動作會比所有的Servlet都要早。
所以 web.xml的載入過程是context-param >> listener >> fileter >> servlet
context-param和init-param區別
web.xml裡面可以定義兩種引數: (1)application範圍內的引數,存放在servletcontext中,可以在servlet中通過getServletContext().getInitParameter("fruitName");
在web.xml中配置如下:
<context-param>
<param-name>fruitName</param-name>
<param-value>orange</param-value>
</context-param>
(2)servlet範圍內的引數,只能在servlet的init()方法中通過this.getInitParameter("fruitName")取得.
在web.xml中配置如下:
<servlet>
<servlet-name>PersonServlet</servlet-name>
<servlet-class>com.king.servlet.PersonServlet</servlet-class>
<init-param>
<param-name>fruitName</param-name>
<param-value>watermelon</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
ContextLoderListener配置
- <param-name>contextConfigLocation</param-name>為固定寫法.
- <param-value></param-value>中可以通過classpath或/WEB-INF 兩種路徑來載入xml檔案.
<!-- application範圍內的引數,存放在ServletContext中 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<!--加入Spring總體配置檔案-->
classpath:config/applicationContext.xml
<!-- /WEB-INF/classes/applicationContext.xml,/WEB-INF/classes/spring-srevlet.xml -->
</param-value>
</context-param>
<!-- Spring監聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
filter配置
說明都在註釋中
<!-- 配置Spring框架自身的攔截器 解決亂碼問題 -->
<filter>
<filter-name>SpringCharacterEncodingFilter</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>SpringCharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
servlet配置
說明都在註釋中
<servlet>
<!-- DispatcherServlet會預設載入WEB-INF/[DispatcherServlet的Servlet名字]-servlet.xml配置檔案 -->
<servlet-name>springServlet</servlet-name>
<!-- 把所有請求交給Spring Web MVC框架處理 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 下面的配置最好直接在一行,且不要有空格,如果輸成 "classpath:空格config/applicationContext.xml" By朱青 -->
<!-- 將會報錯:org.xml.sax.SAXParseException: Content is not allowed in prolog. -->
<param-value>classpath:config/spring/springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<!-- 1)load-on-startup元素標記容器是否在啟動的時候就載入這個servlet(例項化並呼叫其init()方法)。
2)它的值必須是一個整數,表示servlet應該被載入的順序
2)當值為0或者大於0時,表示容器在應用啟動時就載入並初始化這個servlet;
3)當值小於0或者沒有指定時,則表示容器在該servlet被選擇時才會去載入。
4)正數的值越小,該servlet的優先順序越高,應用啟動時就越先載入。
5)當值相同時,容器就會自己選擇順序來載入。 -->
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
註解,定時任務等xml配置在哪載入合適?
如果您把上面的段落都仔細閱讀完了,會發現<servlet>配置如果<load-on-startup>沒有手動配置,那麼預設是servlet第一次被訪問到才會去初始化的,如果該servlet等web應用啟動後,過了很久都沒有被訪問,那麼註釋和定時任務都是不會啟動的.
而且我們應當小心listener和servlet重複載入註解引起的啟動時間浪費 及 重複載入定時任務引起的資料衝突或不一致.
所以註解,定時任務都建議放在全域性監聽的<context-param>中,而不建議放在<servlet>的<init-param>中.
BeanFactory獲取
在EE web應用的servlet或controller中,可通過WebApplicationContextUtils來獲取BeanFactory
BeanFactory factory = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext()); UserManager userManager = (UserManager)factory.getBean("userManager");
在SE 標準應用中可直接通過java程式碼來獲取BeanFactory
BeanFactory factory = new ClassPathXmlApplictionContext("applicationContext.xml");
真實環境web.xml,applicationContext.xml,springMVC.xml
web.xml
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SpringMVC</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>500</error-code>
<!-- <exception-type>java.lang.NullPointerException</exception-type> --> <!-- 還有一種配置是指定異常跳轉 -->
<location>/WEB-INF/jsp/common/errorPage.jsp</location>
</error-page>
<!-- 基礎總配置檔案位置 -->
<!-- application範圍內的引數,存放在ServletContext中 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<!--加入Spring總體配置檔案-->
classpath:config/applicationContext.xml
<!-- /WEB-INF/classes/applicationContext.xml,/WEB-INF/classes/spring-srevlet.xml -->
</param-value>
</context-param>
<!-- Spring監聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- log4j configuration load -->
<servlet>
<servlet-name>log4jInit</servlet-name>
<servlet-class>config.log.Log4jInit</servlet-class>
<init-param>
<param-name>log4j-config-file</param-name>
<param-value>/WEB-INF/classes/config/log/log4j.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置Spring框架自身的攔截器 解決亂碼問題 -->
<filter>
<filter-name>SpringCharacterEncodingFilter</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>SpringCharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<!-- DispatcherServlet會預設載入WEB-INF/[DispatcherServlet的Servlet名字]-servlet.xml配置檔案 -->
<servlet-name>springServlet</servlet-name>
<!-- 把所有請求交給Spring Web MVC框架處理 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 下面的配置最好直接在一行,且不要有空格,如果輸成 "classpath:空格config/applicationContext.xml" By朱青 -->
<!-- 將會報錯:org.xml.sax.SAXParseException: Content is not allowed in prolog. -->
<param-value>classpath:config/spring/springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<!-- 1)load-on-startup元素標記容器是否在啟動的時候就載入這個servlet(例項化並呼叫其init()方法)。
2)它的值必須是一個整數,表示servlet應該被載入的順序
2)當值為0或者大於0時,表示容器在應用啟動時就載入並初始化這個servlet;
3)當值小於0或者沒有指定時,則表示容器在該servlet被選擇時才會去載入。
4)正數的值越小,該servlet的優先順序越高,應用啟動時就越先載入。
5)當值相同時,容器就會自己選擇順序來載入。 -->
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- session超時 -->
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>
<!-- 啟動spring註解,當自動掃描啟動後,該配置可以去掉 -->
<context:annotation-config />
<!-- 自動掃描 -->
<context:component-scan base-package="com.bobo.code" />
<!-- 6. 不同環境之間切換配置檔案,可以讀取該配置檔案的${test.jdbc.username}代表key去取value ,
[1]. 在Spring的Bean定義中使用
[2]. 也可用於Spring在java程式碼中的註解
-->
<!-- <context:property-placeholder location="classpath:/config/database/mysql_jdbc.properties" /> -->
<context:property-placeholder location="classpath:/config/database/oracle_jdbc_virtual_tele.properties" />
<!--DataBase Configuration -->
<!-- Spring的事務管理器有5個,都實現了PlatformTransactionManager介面
DataSourceTransactionManager JDBC事務管理器
HibernateTransactionManager Hibernate事務管理器
JdoTransactionManager JDO事務管理器
JtaTransactionManager JTA事務管理器
PersistenceBrokerTransactionManager Apache的OJB事務管理器 -->
<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${dataSource.driverClassName}" />
<property name="url" value="${dataSource.url}" />
<property name="username" value="${dataSource.username}" />
<property name="password" value="${dataSource.password}" />
</bean>
<!-- 7. 配置myBatis客戶端 -->
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation">
<value>classpath:config/mybatis/sqlmap-config.xml</value>
</property>
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 表示事務的開始策略。
propagation="REQUIRED" 表示name的那個方法必須要在一個事務的環境中執行。
read-only="true" 表示只讀事務,就是不涉及到資料的修改,只是查詢,這是對事務的優化。
-->
<!-- 配置事務的傳播特性 -->
<!-- 8. 配置事務的傳播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- 10. 配置哪些類哪些方法使用事務<aop:pointcut id="allManagerMethod" expression="execution(* com.test.server.dao.*.impl.*(..))"/> -->
<aop:config>
<aop:pointcut id="allManagerMethod" expression="execution(* com.bobo.code.service.impl.*.*(..))" />
<aop:advisor pointcut-ref="allManagerMethod" advice-ref = "txAdvice"/>
</aop:config>
<!--
<import resource="classpath*:config/spring/dataSource.xml"/>
<import resource="classpath*:config/spring/spring-bean.xml"/> -->
<import resource="classpath*:config/spring/timetrigger.xml"/>
</beans>
springMVC.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- MVC -->
<!-- 通過Web.xml的DispatcherServlet載入 -->
<!-- 會自動註冊DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter 兩個bean,是spring MVC為@Controllers分發請求所必須的 -->
<!-- <mvc:annotation-driven /> -->
<!-- 2. 元件掃描路徑配置,讓Spring 容器知道需要掃描哪些包路徑下可以載入到容器中的類 -->
<!-- 多個掃描路徑配置 base-package="com.app,com.core,JUnit4" 也可以寫多份,一般直接寫多份 -->
<context:component-scan base-package="com.bobo.code" />
<!-- 啟動spring事務註解, $該啟用必須在springMVC中,而不能在applicationContext.xml中配置,不然事務註解無效$
也就是說只有這一行才能真正開啟事務,單獨地在類或方法上註解@Transaction只是作了事務標記而以-->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 3. 處理在類級別上的@RequestMapping註解 -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<!-- 多個攔截器,順序執行 -->
<!-- <ref bean="SpringMVCInterceptor" /> -->
<!-- <ref bean="OpenSessionInViewInterceptor" /> -->
</list>
</property>
</bean>
<!-- 4.處理方法級別上的@RequestMapping註解 -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean
class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService">
<bean
class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
</property>
</bean>
</property>
</bean>
<!-- 5.對模型檢視名稱的解析,即給模型檢視名稱新增前後綴 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" /> <!-- 讓ModelAndView("jsp/teacher/listTeachers.jsp") 從/WEB-INF/目錄下開始 -->
<property name="suffix" value="" />
<!-- <property name="suffix" value=".jsp" /> -->
<!-- Spring內部資源解析類 -->
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView" />
</bean>
<!-- 6.異常解析器 -->
<bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">jsp/common/exception</prop>
</props>
</property>
</bean>
</beans>
遺留問題(目前未知原因)
在我的一個spring 遠端方法呼叫的 測試專案中,xml配置檔案只能放在servlet中去訪問才能生效,如果放在context中直接報404異常(404代表應該能訪問到,但是不存在該servlet地址). 只能猜測,不用該servlet就無法讓外部應用訪問到該地址,也許地址必須通過servlet的暴露才能訪問到.