Spring源码-初始化配置(1)
项目整体结构:
配置文件如下:
首先是web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/spring-*.xml</param-value>
</context-param>
<!-- 监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 字符编码过滤器 :只负责解决POST请求乱码问题.-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
<!--
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
-->
</filter-mapping>
<!-- 支持RESTful风格.将POST请求转换为PUT或DELETE请求.会读取隐含参数: "_method" -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>springmvc</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- URL : http://localhost:8080/contextPath/order/save.action -->
<!-- 精确匹配<url-pattern>/user/save</url-pattern>-->
<!-- 路径匹配 -->
<!--
<url-pattern>/user/*</url-pattern>
<url-pattern>/*</url-pattern>
-->
<!-- 扩展匹配 -->
<url-pattern>*.do</url-pattern>
<!-- 默认匹配<url-pattern>/</url-pattern>-->
</servlet-mapping>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<!-- 会话超时时间 -->
<session-config>
<session-timeout>60</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
此处配置spring的监听器:
<!--它的作用是创建spring的IOC容器,IOC容器对象放在Application域里
通过:WebApplicationContextUtils.getApplicationContext(application);
方法获取ioc的容器对象
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
看一下该类的源码
可以看到ContextLoaderListener类实现了ServletContextListener接口
我们知道ServletContextListener接口的作用是监听ServletContext对象的创建和销毁,此时,得出结论,ContextLoaderListener类是监听ServletContext对象的生命周期,在监听到ServletContext对象创建的时候(也就是服务器启动的时候)去创建IOC容器,在ServletContext对象销毁的时候(服务器关闭的时候销毁)
进入ContextLoaderListener类可以看见有两个方法
此时,我们进入初始化方法中的看一看initWebApplicationContext()方法做了什么
该方法获取一个ServletContext的上下文对象,通过getAttribute获取一个属性,如果该属性不为空,则抛出一个异常
继续往下走
该属性为容器初始化的起始时间,结束时间减去起始时间就是我们IOC容器初始化所用的时间
再往下走可以看到
该对象时干嘛的呢,让我们跟进去一探究竟
可以看到
这个WebApplicationContext类是干嘛的呢?它就是我们的IOC容器,回到上面,如果该对象==null
那么就创建我们的IOC容器,该容器的具体类型就是XmlWebApplicationContext类型
此时IOC容器虽然已经创建了,但容器中的bean对象还未创建,我们来看看它们是何时创建的
此处判断context对象是否继承自WebApplicationContext接口
此处判断当前容器是否有父容器,如果当前容器没有父容器,那么当前容器就是父容器
就是该方法里进行了IOC容器的初始化操作,我们跟进去看一看
在此处,初始化了contextConfigLocation,那么我们的上下文中有没有这个初始化参数呢?
回到web.xml
可以看到,我们在web.xml中配置好了该对象,所以可以得出结论,我们的IOC容器在创建的时候会根据我们的配置文件来初始化容器,根据我们所指定的上下文参数来读取我们的spring配置来进行初始化。
这里提一下,该项目是个web项目,classpath后的*代表扫描所有jar包下的类路径中的spring-开头的配置文件,如果不加这个*则只会扫描本项目的类路径
再往后看
此处获取到contextConfigLocation的配置之后,判断该对象是否为空,如果该对象存在,再将该配置都封装给wac该IOC容器对象,此时我们进入该对象看一看
可以看到在XmlWebApplicationContext中有一个默认常量,当没有配置上下文参数的时候,默认去WEB-INF/applicationContext.xml中读取配置,这里因为我们已经在web.xml中配置了上下文读取的配置文件,所以不会走默认的路径读取
回到ContextLoader再往下走
进入refresh
可以看到IOC容器在初始化Bean时是进行一个synchronized同步操作的,至于其初始化的细节,这里就不一 一赘述了。有兴趣的自己可以看下
https://my.oschina.net/sunhacker/blog/870728