最近抽空看了下spring源码,我们一起从web容器启动开始,一步一步分析spring是如何被拉起,如何加载加载其配置文件,如何使用加载到容器上下文中的对象

web.xml

web.xml中的spring容器配置

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

ContextLoaderListner如何拉起?

ContextLoaderListener是spring核心功能启动器,该监听器会监听Servlet容器启动事件,一旦监听到该事件就拉起spring整个容器的启动。

  • ContextLoaderListener实现了javax.servlet.ServletContextListener接口,该接口的contextInitialized方法用来对扩展的容器进行初始化,ContextLoaderListener在该方法中对spring上下文进行初始化。
  • ContextLoaderListener继承ContextLoader,ContextLoader.initWebApplicationContext方法创建容器Context,并且调度配置文件加载。

ContextLoader.initWebApplicationContext方法中Context创建代码如下:

 if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

初始化容器时需要判断容器是否已经初始化过,如果没有则创建一个新的spring容器

容器创建流程如下:

ContextLoader会首先从ServletContext中获取配置的容器类(参数名:contextClass)

如果获取不到则使用ContextLoader同一classPath下的ContextLoader.properties中的配置。

将org.springframework.web.context.WebApplicationContext对应的值作为容器类并实例化容器作为spring的根容器。ContextLoader.properties配置如下:

Context创建

创建Context实例,刷新Context。

刷新Context:创建Bean工厂,调用ResourceReader加载Spring的bean配置,将每个bean配置构建成一个BeanDefinition对象存储到Bean工厂,bean配置加载完成后需要给Bean工厂设置一系列postProccessor,执行这些Proccessor,Context在postProccessor处理完成后对所有“非懒加载”的单例bean对象进行实例化。实例化后执行BeanPostProcessor的BeanPostProcessorsBeforeInitialization方法,而后对指定了init方法的实例调用init方法,或者对实现了InitializingBean接口的bean调用afterPropertiesSet方法,初始化方法后执行BeanPostProcessor的applyBeanPostProcessorsAfterInitialization方法。实例化结束后向所有监听器推送ContextRefreshedEvent事件。其中供bean实例使用的BeanPostProcessor是ApplicationListenerDetector,通过该Proccessor,bean可以自定义init方法调用前后执行的动作。init执行前可以通过实现InitializingBean接口,init执行后可以通过实现ApplicationListener接口。

Bean工厂继承关系:

对于bean的具体实例化、初始化、

默认的XmlWebApplicationContext

XmlWebApplicationContext实例化后被存放到ServletContext中,缓存使用的key为:org.springframework.web.context.WebApplicationContext.ROOT

在web服务中只要能获取到ServletContext就可以根据WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE获取spring根Context

XmlWebApplicationContext实例化成功后,ContextLoader会调用configureAndRefreshWebApplicationContext对容器上下文进行配置和初始化

其中就包括Spring基本属性设置、配置文件加载,解析,对象实例化等动作。Spring容器上下文继承关系如下:

XmlWebApplicationContext的配置文件加载,解析,对象实例化等动作都统一在AbstractApplicationContext.refresh方法中完成

refresh结束后,容器会发布一个ContextRefreshedEvent事件,供依赖容器启动结束的组件或者第三方定制扩展使用(例如Dubbo,通过监听该事件触发其配置加载后的实例包装动作)。

具体的刷新核心代码我们看一下:

// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
finishRefresh();
}

  

BeanFactory

容器刷新涉及最终要的部件是ApplicationContext辅助类以及beanFactory,ApplicationContext负责spring配置文件的加载和解析,将bean配置解析转换成一个个BeanDefinition并传递给bean工厂,bean工厂调度ApplicationContext辅助类的解析工作,并在解析完成后负责bean对象实例化。

obtainFreshBeanFactory方法完成工厂创建和刷新,工厂刷新工作内容主要是调度ApplicationContex将bean配置解析转换成一个个BeanDefinition,具体的配置解析和加载工作实现在不同的ApplicationContext实现类,例如xml解析在XmlWebApplicationContext中定义。

org.apache.xbean.spring.context.XmlWebApplicationContext中的配置加载如下:

通过调用父类org.springframework.web.context.support.XmlWebApplicationContext的loadBeanDefinitions实际完成加载工作,其实所有ApplicationContext的对应的配置加载实现都在org.springframework.web.context.support包下面:

org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver负责加载spring配置文件解析器信息配置

扩展NameSpaceHandler

DefaultNamespaceHandlerResolver默认从classpath中META-INF/spring.handler文件中读取配置文件解析器映射关系
spring.handler中的配置如下:

其中配置了配置文件命名空间和NamespaceHandler类的映射关系。

NamespaceHandler中定义了不同类型xml节点的解析器。容器启动过程中XmlWebApplicationContext会通过XmlBeanDefinitionReader读取Spring的配置文件,在解析每一个配置节点时,会从NamespaceHandler中获取对应的解析器进行解析并转换成Spring容器中的实例或者spring配置对象。

Spring源码阅读-spring启动的更多相关文章

  1. (转) Spring源码阅读 之 Spring整体架构

    标签(空格分隔): Spring 声明:本文系转载,原地地址:spring framework 4 源码阅读 Spring骨架 Spring的骨架,也是Spring的核心包.主要包含三个内容 cont ...

  2. Spring源码阅读-ApplicationContext体系结构分析

    目录 继承层次图概览 ConfigurableApplicationContext分析 AbstractApplicationContext GenericApplicationContext Gen ...

  3. Bean实例化(Spring源码阅读)-我们到底能走多远系列(33)

    我们到底能走多远系列(33) 扯淡: 各位:    命运就算颠沛流离   命运就算曲折离奇   命运就算恐吓着你做人没趣味   别流泪 心酸 更不应舍弃   ... 主题: Spring源码阅读还在继 ...

  4. 初始化IoC容器(Spring源码阅读)

    初始化IoC容器(Spring源码阅读) 我们到底能走多远系列(31) 扯淡: 有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的.未婚的你们,你们是怎么分配工资的? ...

  5. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

  6. Spring源码阅读笔记02:IOC基本概念

    上篇文章中我们介绍了准备Spring源码阅读环境的两种姿势,接下来,我们就要开始探寻这个著名框架背后的原理.Spring提供的最基本最底层的功能是bean容器,这其实是对IoC思想的应用,在学习Spr ...

  7. Spring源码阅读 之 配置的读取,解析

    在上文中我们已经知道了Spring如何从我们给定的位置加载到配置文件,并将文件包装成一个Resource对象.这篇文章我们将要探讨的就是,如何从这个Resouce对象中加载到我们的容器?加载到容器后又 ...

  8. 搭建 Spring 源码阅读环境

    前言 有一个Spring源码阅读环境是学习Spring的基础.笔者借鉴了网上很多搭建环境的方法,也尝试了很多,接下来总结两种个人认为比较简便实用的方法.读者可根据自己的需要自行选择. 方法一:搭建基础 ...

  9. Spring源码阅读总结(Ing)

    一.Spring源码架构 Spring源码地址 二.Spring中的设计模式 1.工厂模式 BeanFactory 2.模板模式 模板的使用者只需设计一个具体的类,集成模板类,然后定制那些具体方法,这 ...

随机推荐

  1. 去中心化类微博应用 mastodon

    一句话重点,去中心,没监管,自己对自己信息做主,没人随便删你消息的分布式社交应用 mastodon. 建了一个实例, https://cncs.io 来专门讨论计算机相关信息,欢迎大家注册来玩.已有用 ...

  2. FineUI控件集合

    FineUI(开源版)基于 ExtJS 的开源 ASP.NET 控件库. using System; using System.Collections.Generic; using System.Te ...

  3. Ubuntu14.04上修改主机名

    Ubuntu14.04上修改主机名 author:headsen chen  2017-10-12 15:41:31 个人原创,转载请注明作者,出处,否则依法追击法律责任 查看主机名:hostname ...

  4. Laravel框架中的make方法详解

    为什么网上已经有这么多的介绍Laravel的执行流程了,Laravel的容器详解了,Laravel的特性了,Laravel的启动过程了之类的文章,我还要来再分享呢? 因为,每个人的思维方式和方向是不一 ...

  5. response重定向的网址中有中文乱码的解决办法

    在servlet都是使用response对象来重定向到另一个页面:response.sendRedirect("--").现在遇到一个问题,网页的地址是带中文的,当执行到跳转命令的 ...

  6. [SCOI2011] 糖果

    luogu Description 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到 ...

  7. Tomcat下wtpwebapps文件夹 和 webapps文件夹区别

    这两者其实没有区别.都是项目部署路径 webapps : tomcat默认部署路径 wtpwebapps : eclipse默认部署路径 只不过Tomcat6将wtpwebapps作为了默认路径,如果 ...

  8. spring-boot 多模块化项目和EurekaServer的搭建

    Spring boot由于其 1.易于开发和维护.2.单个微服务启动快.3.局部修改部署容易.4.技术栈不受语言限制等优点受到越来越多公司的重视.spring-boot还集成了许多关于微服务开发的框架 ...

  9. 大数据 --> 一致性Hash算法

    一致性Hash算法 一致性Hash算法(Consistent Hash)

  10. C语言的字符串操作函数小结

    一.strcat()函数 char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾.它返回一个指向字符串de ...