1. 程式人生 > >spring監聽器ContextLoaderListener的疑問

spring監聽器ContextLoaderListener的疑問

今天新搭了專案,採用Spting和mybatis,MVC用的是Spring MVC ,配置檔案採用的是之前的專案的。

在執行後訪問專案時候報錯了:

java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?

在研究後發現是web.xml缺少了Spring監聽器:

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:beans.xml</param-value>
  </context-param>
這裡就有個疑問了,為什麼之前專案不加這一段執行正常。

經過研究後發現是新專案載入了shiro過濾器:

<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>/*</url-pattern>
		<dispatcher>REQUEST</dispatcher>
		<dispatcher>FORWARD</dispatcher>
	</filter-mapping>
該過濾器的功能需要依賴ContextLoaderListener所載入的beans.xml檔案生成的applicationContext即Spring的上下文,而之前DispatcherServlet所載入的beans.xml檔案生成的applicationContext為Spring mvc的上下文,shiro過濾器無法載入,所以得依靠監聽器載入public的applicationContext。

附三個context的關係:

  1. 對於一個web應用,web容器載入一個全域性context供其使用,這個context就是servletContext,為其後續的spring IoC容器提供依賴。

  2. 在web.xml中提供的ContextLoaderListener監聽器,web容器啟動時會觸發容器初始化事件,ContextLoaderListener會監聽這個事件,初始化一個根上下文即WebApplicationContext,實現類為XmlWebApplicationContext。這個就是Spring的IoC容器,spring將其以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE為key儲存在servletContext中
  3. DispatcherServlet在初始化會建立自己的IoC容器用以持有Spring mvc相關的bean,它在建立的時候會通過WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從servletContext中獲取根上下文作為自己上下文的父上下文,它的實現類也是XmlWebApplicationContext,在建立之後會以和自己servlet-name便籤有關的名稱儲存在servletContext中,這樣每個servlet就擁有自己獨立的bean及根上下文共享的bean

但是這樣會導致重複載入配置檔案,DispatcherServlet、ContextLoaderListener會分別載入一次,解決方法是把配置檔案拆分成2個,一個Spring mvc的配置檔案,一個Spring的配置檔案,DispatcherServlet載入Spring mvc的配置檔案,ContextLoaderListener載入Spring的配置檔案 。

Spring mvc在使用上下文的時候會使用DispatcherServlet載入的applicationContext,也會使用的contextLoaderListener載入的applicationContext。