详述SpringMVC中ContextLoaderListener监听器

Table of Contents

一、配置

二、原理

1.监听器中执行原理

2.DispatchServlet加载时执行原理

三、Root WebApplicationContext和Servlet WebApplicationContext


一、配置

org.springframework.web.servlet.DispatcherServlet的配置除了常规的配置方法以外,还可以使用ContextLoaderListener监听器进行配置,如下:

第11-14行:contextConfigLocation用于指定Spring的配置文件

第15-17行: 配置spring核心监听器,默认会以 /WEB-INF/applicationContext.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>springsun</display-name>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

	<context-param> 
		<param-name>contextConfigLocation</param-name> 
		<param-value>classpath:app*.xml</param-value> 
	</context-param> 
	<listener> 
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
	</listener> 
	<servlet> 
		<servlet-name>DispatcherServlet</servlet-name> 
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
		<init-param> 
			<param-name>contextAttribute</param-name> 
			<param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value> 
		</init-param> 
		<load-on-startup>1</load-on-startup> 
	</servlet> 
	<servlet-mapping> 
		<servlet-name>DispatcherServlet</servlet-name> 
		<url-pattern>*.do</url-pattern> 
	</servlet-mapping>
</web-app>

二、原理

1.监听器中执行原理

首先进入ContextLoaderListener类中,因为该类实现了javax.servlet.ServletContextListener接口,所以Tomcat发布Web应用时执行该类contextInitialized方法:

该方法中执行了initWebApplicationContext方法,参数为ServletContext类对象,即application对象

再进入initWebApplicationContext方法中,该方法是ContextLoaderListener继承自父类ContextLoader的方法:

第295行:判断ServletContext对象,即application对象是否已经存放了XmlWebApplicationContext实例,其中常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为WebApplicationContext全类名与“.ROOT”拼接而成的字符串,即org.springframework.web.context.WebApplicationContext.ROOT;

第312行:createWebApplicationContext方法利用反射的方式创建XmlWebApplicationContext对象,并赋值给context变量;

第314行:由于XmlWebApplicationContext类间接实现了ConfigurableWebApplicationContext接口,所以该处if条件为true;

第315行:将context变量中XmlWebApplicationContext变量强制类型转换为ConfigurableWebApplicationContext类型;

第316行:由于cwac变量中对象尚未加载配置文件,所以进入代码块;

第325行:加载配置文件;

第328行:将context变量中的XmlWebApplicationContext对象保存至application内置对象中,保存的变量名即为org.springframework.web.context.WebApplicationContext.ROOT;

第347行:返回XmlWebApplicationContext示例对象;

接下来再来分析上面第325行中的configureAndRefreshWebApplicationContext方法的源代码:

第428行:为wac绑定ServletContext对象

第429行:此处常量CONFIG_LOCATION_PARAM为字符串contextConfigLocation,即获取web.xml配置文件中context-param标签key为contextConfigLocation的value值,上述配置中该value值为classpath:app*.xml

2.DispatchServlet加载时执行原理

DispatchServlet加载完整过程见博客:SpringMVC中load-on-startup标签的执行过程

Tomcat发布Web应用时依次执行init方法—>initServletBean方法—>执行initWebApplicationContext方法:

第549行:findWebApplicationContext用于在application内置对象中寻找已有的WebApplicationContext对象;

第553行:如果此时wac为null则说明第549行在application内置对象中未找到WebApplicationContext对象,则重新创建一个WebApplicationContext对象;

接下来进入findWebApplicationContext方法分析源码:

第587行:将web.xml配置文件中配置的DispatchServlet时配置的param-name标签key为contextAttribute的value值,此处为配置的org.springframework.web.context.WebApplicationContext.ROOT

第591-592行:getWebApplicationContext方法用于获取application内置对象中保存到的XmlWebApplicationContext对象

接下来再进入getWebApplicationContext方法分析源码:

第109行:attrName即为传入的org.springframework.web.context.WebApplicationContext.ROOT字符串,调用getAttribute方法即可获取application内置对象中保存的XmlWebApplicationContext对象;

第125行:将得到的XmlWebApplicationContext对象返回;

三、Root WebApplicationContextServlet WebApplicationContext

前面例子我们将Spring相关配置和SpringMVC相关配置一股脑写在了一个xml配置文件,试想如果需要配置的东西很多,那么该文件势必很长,势必很乱,为了解决这一诟病需要按照配置的不同创建两个配置文件:一个配置文件专门用于Spring相关配置;一个配置文件专门用于SpringMVC相关配置,如下:

root-context.xml:该文件仅用于实例化Service层和Dao层,用于数据库相关配置:

<?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:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	
	<!--仅仅实例化被@Component、@Service或@Repository等注解所修饰的类 -->
	<context:component-scan base-package="com.jd">
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" lazy-init="false" destroy-method="close">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8"></property>
		<property name="username" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	
	<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"></bean>
	<tx:annotation-driven/>
	
	<bean class="org.mybatis.spring.SqlSessionFactoryBean" 	p:dataSource-ref="dataSource" p:configLocation="classpath:mybatis-config.xml"
		p:mapperLocations="classpath:/sql/*.xml">
	</bean>
	
	<mybatis-spring:scan base-package="com.jd.*.dao" />
</beans>

servlet-context.xml:该文件仅用于实例化Controller层,用于视图解析器等SpringMVC相关配置:

<?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:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	
	<!-- 仅实例化被@Controller等注解所修饰的类 -->
	<context:component-scan base-package="com.jd" use-default-filters="false">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/view/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:defaultEncoding="UTF-8" p:maxUploadSize="10241000">
	</bean>
	
	<mvc:annotation-driven></mvc:annotation-driven>
</beans>

此时在web.xml配置文件中就需要对root-context.xml和servlet-contxt.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>cassini</display-name>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
	
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
    
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:root-context.xml</param-value>
	</context-param>
    
	<servlet>
		<servlet-name>DispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>DispatcherServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值