ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");

Spring加载xml数据的切入点是通过ClassPathXmlApplicationContext类进行切入的。该类是面向xml文件。类似的spring还提供了面向注解的解析类AnnotationConfigApplicationContext等。

进入

new ClassPathXmlApplicationContext("spring-config.xml");

之后代码如下:

public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {

super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}

Spring容器的加载、xml文件的解析器以及单例、非懒加载的类等都是由refresh()方法完成。Refresh代码如下所示:

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      //准备刷新环境列入对系统属性或者环境变量进行准备及验证
      prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
      /* 调用子类AbstractRefreshableApplicationContext 刷新DefaultListableBeanFactory工厂
       * 功能描述  1、创建核心组件ConfigurableListableBeanFactory
       * 2、获取xml、注解等方式的配置,将其转换为原数据放入ConfigurableListableBeanFactory中
       * 3、xml读取
       */
      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();
      }

catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

// Destroy already created singletons to avoid dangling resources.
         destroyBeans();

// Reset 'active' flag.
         cancelRefresh(ex);

// Propagate exception to caller.
         throw ex;
      }

finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

如代码所示xml数据的读取主要是在obtainFreshBeanFactory()方法中进行处理的。而AbstractApplicationContext类中并没有对obtainFreshBeanFactory()方法做具体的实现,而是将其交由子类AbstractRefreshableApplicationContext去实现

Xml的读取主要处理2个问题

1、准备容器,用于存储解析后的数据

2、准备documentReader,用于解析spring配置文件

代码如下:

@Override
protected final void refreshBeanFactory() throws BeansException {
   /**
    * DefaultListableBeanFactory被实例化至少一次时将销毁spring创建的对象,并且关闭DefaultListableBeanFactory实例
    */
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      DefaultListableBeanFactory beanFactory = createBeanFactory();//创建spring的核心组件
      //为了序列化指定id
      beanFactory.setSerializationId(getId());
      //定制beanFactory,设置相关属性。
      customizeBeanFactory(beanFactory);
      //初始化xml读取器、读取原数据切入点  交由子类处理
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

该方法主要完成以下几个工作:

1、校验DefaultListableBeanFactory被实例化至少一次时将销毁spring创建的对象,并且关闭DefaultListableBeanFactory实例

2、创建spring的核心组件DefaultListableBeanFactory的具体实例并设置相应参数,也就是beanFactory。

3、初始化xml读取器、读取xml数据切入点  交由子类处理。

4、将beanFactory设定为全局变量。

AbstractRefreshableApplicationContext并没有对loadBeanDefinitions()方法进行具体的实现,而是将其交由子类去做处理,这样做的好处是针对不同的spring配置方式采用不同的解析方式进行解析(策略模式)。

Ps:此处只针对xml文件的配置(AbstractXmlApplicationContext)解析进行说明

上面部分代码完成了对beanFactory的定制,并且对xml文件的解析做了切入loadBeanDefinitions();

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   /*依据beanFactory创建新的XmlBeanDefinitionReader */
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context's
   // resource loading environment.
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.
   initBeanDefinitionReader(beanDefinitionReader);
   loadBeanDefinitions(beanDefinitionReader);
}

以上代码完成以下功能

1、为特定的beanFactory准备相应的beanDefinitionReader 并完成相应设置

2、切入loadBeanDefinitions();

Xml文件的解析是交由专门的解析类AbstractBeanDefinitionReader进行处理。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
   }
}

Ps:读者可参考此图

五、spring源码阅读之ClassPathXmlApplicationContext加载beanFactory的更多相关文章

  1. 【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  2. 【Spring源码分析】Bean加载流程概览(转)

    转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...

  3. Spring源码分析:Bean加载流程概览及配置文件读取

    很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...

  4. Spring源码解析-配置文件的加载

    spring是一个很有名的java开源框架,作为一名javaer还是有必要了解spring的设计原理和机制,beans.core.context作为spring的三个核心组件.而三个组件中最重要的就是 ...

  5. 【Spring源码分析系列】加载Bean

    /** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * ...

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

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

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

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

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

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

  9. 37 网络相关函数(五)——live555源码阅读(四)网络

    37 网络相关函数(五)——live555源码阅读(四)网络 37 网络相关函数(五)——live555源码阅读(四)网络 简介 10)MAKE_SOCKADDR_IN构建sockaddr_in结构体 ...

随机推荐

  1. 基于FPGA的SPI FLASH控制器设计

    1.SPI FLASH的基本特征 本文实现用FPGA来设计SPI FLASH,FLASH型号为W25Q128BV.支持3种通信方式,SPI.Dual SPI和Quad SPI.FLASH的存储单元无法 ...

  2. $CH5501$ 环路运输 环形$+$单调队列

    CH Description 在一条环形公路旁均匀地分布着N座仓库,编号为1~N,编号为 i 的仓库与编号为 j 的仓库之间的距离定义为 dist(i,j)=min⁡(|i-j|,N-|i-j|),也 ...

  3. centos 7.3 服务器环境搭建——MySQL 安装和配置

    centos 7.3 服务器环境搭建——MySQL 安装和配置服务器信息如下:服务器:阿里云系统 centos 7.3 (阿里云该版本最新系统)mysql版本:5.7.18 (当前时间最新版本)连接服 ...

  4. JAVA8学习——Stream底层的实现(学习过程)

    Stream底层的实现 Stream接口实现了 BaseStream 接口,我们先来看看BaseStream的定义 BaseStream BaseStream是所有流的父类接口. 对JavaDoc做一 ...

  5. Dockerfile + Nginx.conf文件记录(用于前端项目部署)

    Dockerfile + Nginx.conf文件记录(用于前端项目部署) 本教程依据个人理解并经过实际验证为正确,特此记录下来,权当笔记. 注:基于linux操作系统(敏感信息都进行了处理),默认服 ...

  6. Cannot access org.springframework.context.ConfigurableApplicationContext

    Cannot access org.springframework.context.ConfigurableApplicationContext 需要将有问题的模块  删除 后重新导入 即可 IDEA ...

  7. vue将接口返回的日期实时转换为几分钟前、几小时前、几天前

    项目开发中,各种需求都会遇到,有些需求很合理,也好实现,有些需求不能说不合理,就是太麻烦,就比如类似标题所描述这种的需求,你不能说它是不合理的需求,因为很多论坛或微博.朋友圈.QQ空间之类的这种效果还 ...

  8. 代码注释规范-IDEA 配置 Java 类方法注释模板

    1. 引言     团队开发时,业务模块分配的越清晰,代码注释管理越完善,越有利于后面维护,后面再管理也方便不少.另外也起着"文字砖"的作用,你懂的.注释不需要很详细,把代码块方法 ...

  9. vnpy源码阅读学习(2):学习PyQt5

    PyQt5的学习 花费了一个下午把PyQt5大概的学习了下.找了一个教程 PyQt5教程 跟着挨着把上面的案例做了一遍,大概知道PyQt5是如何生成窗体,以及控件的.基本上做到如果有需求要实现,查查手 ...

  10. js最简单的编写地点

    1. 在哪里? 在浏览器的控制台. 2. 有什么作用? 方便快捷的测试纯js代码语句. 3. 如何使用? Google浏览器为例:  按 F12键  打开 开发者工具  (或者 浏览器工具栏 => ...