详解contextConfigLocation|Spring启动过程详解
spring的应用初始化流程一直没有搞明白,刚刚又碰到了相关的问题。决定得好好看看这个流程。我们在开发spring的项目当中基本上都会在web.xml通过:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/conf/application-*.xml
</param-value>
</context-param>
来初始化各个spring的配置文件,但是我们只是知道这段代码的功能, 并不是很清楚我们配置了这段代码之后为什么就能去初始化配置文件。当然我们还会加上:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
这一个listener,我首先就会想contextConfigLocation这个一定能在ContextLoaderListener这个类当中找到,打开了源码,这个listener是实现了ServletContextListener这个接口的,这个接口只有两个方法:
public interface ServletContextListener
extends EventListener
{ public abstract void contextInitialized(ServletContextEvent servletcontextevent); public abstract void contextDestroyed(ServletContextEvent servletcontextevent);
}
而且它是继承了EventListener这个接口的,打开这个接口的代码让我大吃一惊,里面没有方法啥都没有:
package java.util; public interface EventListener
{
}
而且还是java.util包下的,并不是spring之中的东西。
这样找了之后没有找到,往回退到ContextLoaderListener这个类的方法上,contextInitialized方法是用来初始化上下文的:
public void contextInitialized(ServletContextEvent event)
{
contextLoader = createContextLoader();
contextLoader.initWebApplicationContext(event.getServletContext());
}
方法中有个createContextLoader方法:
protected ContextLoader createContextLoader()
{
return new ContextLoader();
}
这个方法返回了一个ContextLoader实例,进入到ContextLoader类中,按ctrl+f来寻找contextConfigLocation,这时没有出现电脑的咚的声音,找到了它:
protected WebApplicationContext createWebApplicationContext(ServletContext servletContext, ApplicationContext parent)
throws BeansException
{
Class contextClass = determineContextClass(servletContext);
if(!(org.springframework.web.context.ConfigurableWebApplicationContext.class).isAssignableFrom(contextClass))
{
throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + (org.springframework.web.context.ConfigurableWebApplicationContext.class).getName() + "]");
} else
{
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);
wac.setConfigLocation(servletContext.getInitParameter("<span style="color:#ff0000;">contextConfigLocation</span>"));
customizeContext(servletContext, wac);
wac.refresh();
return wac;
}
}
通过代码,ConfigurableWebApplicationContext设置了从servletContext获取到的参数的值,再进入ConfigurableWebApplicationContext的代码中,它只是一个接口,进入StaticWebApplicationContext的setConfigLocation方法:
public void setConfigLocation(String configLocation)
{
if(configLocation != null)
throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
else
return;
}
这个方法中很奇怪,当参数不为空就抛出异常,查看spring的文档:The StaticWebApplicationContext
class does not support this method.说是此类不支持这个方法,这下子又卡住了。又要退回去,看这句:
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
pring使用BeanUtils来初始化contextClass这个类实例,contextClass是通过以下代码得到的:
protected Class determineContextClass(ServletContext servletContext)
throws ApplicationContextException
{
String contextClassName = servletContext.getInitParameter("contextClass");
if(contextClassName != null)
try
{
return ClassUtils.forName(contextClassName);
}
catch(ClassNotFoundException ex)
{
throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", ex);
}
contextClassName = defaultStrategies.getProperty((org.springframework.web.context.WebApplicationContext.class).getName());
try
{
return ClassUtils.forName(contextClassName, (org.springframework.web.context.ContextLoader.class).getClassLoader());
}
catch(ClassNotFoundException ex)
{
throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", ex);
}
}
这里使用了反射,再来看BeanUtils的instantiateClass方法:
return instantiateClass(clazz.getDeclaredConstructor((Class[])null), null);
通过反射得到contextClass的构造方法。下面是instantiateClass方法的重载,主要是下面两句代码:
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
ctor是通过反射得到的contextClass的构造方法,args是构造方法当中的参数。这里为null,说明new了contextClass的无参构造方法。
这时又要退回到determineContextClass 这个方法中,我们主要看:
contextClassName = defaultStrategies.getProperty((org.springframework.web.context.WebApplicationContext.class).getName());
这句代码,我们可以猜它是通过Properties的getProperty方法得到WebApplicationContext 的实例,这时我们又到了WebApplicationContext 这个接口当中,这个接口继承了ApplicationContext这个接口,我们都知道我们进行spring开发都会通过Application ctx=new FileSystemXmlApplicationContext("beans.xml");或ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");或ServletContext servletContext = request.getSession().getServletContext();ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);这三种方法获得一个ApplicationContext,然后就可以对配置文件当中的bean进行操作了。所以这里我们基本上已经搞清楚初始化spring配置文件的流程了。
总结:通过查看这几个类的源代码,java的反射使用范围之广再次体现出来。如看了之后觉得有错误或者不同意见,欢迎提出来,我也是第一次才研究这个问题。
详解contextConfigLocation|Spring启动过程详解的更多相关文章
- 详解contextConfigLocation|Spring启动过程详解(转)
原文链接:https://blog.csdn.net/qw222pzx/article/details/78191670 spring的应用初始化流程一直没有搞明白,刚刚又碰到了相关的问题.决定得好好 ...
- Linux启动过程详解(inittab、rc.sysinit、rcX.d、rc.local)
启动第一步--加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它.这是因为BIOS中包含了CPU的相关信息.设备启动顺序信息.硬 ...
- Linux启动过程详解
Linux启动过程详解 附上两张图,加深记忆 图1: 图2: 第一张图比较简洁明了,下面对第一张图的步骤进行详解: 加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的 ...
- Android 核心分析 之八Android 启动过程详解
Android 启动过程详解 Android从Linux系统启动有4个步骤: (1) init进程启动 (2) Native服务启动 (3) System Server,Android服务启动 (4) ...
- 【STM32H7教程】第13章 STM32H7启动过程详解
完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第13章 STM32H7启动过程详解 本章教 ...
- fabric网络环境启动过程详解
这篇文章对fabric的网络环境启动过程进行讲解,也就是我们上节讲到的启动测试fabric网络环境时运行network_setup.sh这个文件的执行流程 fabric网络环境启动过程详解 上一节我们 ...
- (转)Linux 开机引导和启动过程详解
Linux 开机引导和启动过程详解 编译自:https://opensource.com/article/17/2/linux-boot-and-startup作者: David Both 原创:LC ...
- linux 开机启动过程详解
Linux开机执行内核后会启动init进程,该进程根据runlevel(如x)执行/etc/rcx.d/下的程序,其下的程序是符号链接,真正的程序放在/etc/init.d/下.开机启动的程序(服务等 ...
- 转-Linux启动过程详解(inittab、rc.sysinit、rcX.d、rc.local)
http://blog.chinaunix.net/space.php?uid=10167808&do=blog&id=26042 1)BIOS自检2)启动Grub/Lilo3)加 ...
随机推荐
- Log4Net记录到数据库
WinForm下Log4Net的配置 Log4Net 组件下载地址 https://download.csdn.net/download/zgx123zgx123zg/10470986 configS ...
- Html Agility Pack解析Html(C#爬虫利器)
有个需求要写网络爬虫,以前接触过一个叫Html Agility Pack这个解析html的库,这次又要用到,然而发现以前咋用的已经不记得了,现在从头开始记录一下使用过程. Html Agility P ...
- Spring static 静态属性注入
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> &l ...
- GoLang学习之Golang数组
Go语言数组 数组是Go语言编程中最常用的数据结构之一.顾名思义,数组就是指一系列同一类型数据的集合.数组中包含的每个数据被称为数组元素( element),一个数组包含的元素个数被称为数组的长度.需 ...
- Linux巩固记录(8) Hbase shell 基本使用
继续前几篇内容,讲解hbase基本使用 1.进入hbase shell: hbase有很多种操作方式,比如shell,java客户端,webUI等,可以直接输入hbase进行提示 [root@mast ...
- C#导出HTML到PDF组件 Pechkin
C#导出PDF功能是开发中经常遇到的功能,我们采用第三方的组件,比如 iTextSharp, aspose等,还能搜到一些开源的类库, 但是对于一些内容复杂样式丰富的PDF,我们希望通过传入一个URL ...
- UICollectionView设置首个cell默认选中
设置UICollectionView中某个cell的默认选中,刚开始为追求性能,采用同一个cellId去标识UICollectionViewCell,却由于cell的重用会导致之前选中的cell在被重 ...
- Spring MVC前后端数据交互总结
控制器 作为控制器,大体的作用是作为V端的数据接收并且交给M层去处理,然后负责管理V的跳转.SpringMVC的作用不外乎就是如此,主要分为:接收表单或者请求的值,定义过滤器,跳转页面:其实就是ser ...
- 【转】iOS中属性与成员变量的区别
[转载自并整理 http://blog.csdn.net/itianyi/article/details/8618128] 一.类Class中的属性property 在ios第一版中,我们为输出口同时 ...
- 《deep sort》复现过程
目录 1. 准备代码与数据 deep_sort开源代码 克隆到本地服务器 git clone https://github.com/nwojke/deep_sort.git 下载MOT16数据集(MO ...