摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。

目录

一、定制化BeanFactory

二、加载BeanDefinition

obtainFreshBeanFactory方法从字面上理解是获取BeanFactory。之前有说过,ApplicationContext是对BeanFactory的功能上的扩展,不但包含了BeanFactory的全部功能更在其基础上添加了大量的扩展功能,那么obtainFreshBeanFactory正是实现BeanFactory的地方,也就是经过了这个函数后ApplicationContext就已经拥有了BeanFactory的全部功能。

  1. /**
  2. * Tell the subclass to refresh the internal bean factory.
  3. * @return the fresh BeanFactory instance
  4. * @see #refreshBeanFactory()
  5. * @see #getBeanFactory()
  6. */
  7. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  8. // 初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中
  9. refreshBeanFactory();
  10. // 返回当前实体的beanFactory属性
  11. return getBeanFactory();
  12. }

方法中将核心实现委托给了refreshBeanFactory:

  1. /**
  2. * This implementation performs an actual refresh of this context's underlying
  3. * bean factory, shutting down the previous bean factory (if any) and
  4. * initializing a fresh bean factory for the next phase of the context's lifecycle.
  5. */
  6. @Override
  7. protected final void refreshBeanFactory() throws BeansException {
  8. if (hasBeanFactory()) {
  9. destroyBeans();
  10. closeBeanFactory();
  11. }
  12. try {
  13. // 创建DefaultListableBeanFactory
  14. DefaultListableBeanFactory beanFactory = createBeanFactory();
  15. // 为了序列话指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
  16. beanFactory.setSerializationId(getId());
  17. /**
  18. * 设置两个属性:
  19. * 1. 是否允许覆盖同名称的不同定义的对象
  20. * 2. 是否允许bean之间存在循环依赖
  21. */
  22. customizeBeanFactory(beanFactory);
  23. // 初始化DocumentReader,并进行XML文件读取和解析
  24. loadBeanDefinitions(beanFactory);
  25. synchronized (this.beanFactoryMonitor) {
  26. this.beanFactory = beanFactory;
  27. }
  28. }
  29. catch (IOException ex) {
  30. throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  31. }
  32. }

我们详细分析上面的每个步骤。

(1)创建DefaultListableBeanFactory。

在介绍BeanFactory的时候,不知道读者是否还有印象,声明方式为:BeanFactory factory = new XmlBeanFactory("spring-test.xml"),其中的XmlBeanFactory继承自DefaultListableBeanFactory,并提供了XmlBeanDefinitionReader类型的reader属性也就是说DefaultListableBeanFactory是容器的基础。必须首先实例化,那么在这里就是实例化DefaultListableBeanFactory的步骤。

(2)指定序列化ID。

(3)定制BeanFactory。

(4)加载BeanDefinition。

(5)使用全局变量记录BeanFactory类实例。

因为DefaultListableBeanFactory类型的变量beanFactory是函数内的局部变量,所以要使用全局变量记录解析结果。

一、定制化BeanFactory

这里已经开始了对BeanFactory的扩展,在基本容器的基础上,增加了是否允许覆盖是否允许扩展的设置。

  1. /**
  2. * Customize the internal bean factory used by this context.
  3. * Called for each {@link #refresh()} attempt.
  4. * <p>The default implementation applies this context's
  5. * {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
  6. * and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
  7. * if specified. Can be overridden in subclasses to customize any of
  8. * {@link DefaultListableBeanFactory}'s settings.
  9. * @param beanFactory the newly created bean factory for this context
  10. * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
  11. * @see DefaultListableBeanFactory#setAllowCircularReferences
  12. * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
  13. * @see DefaultListableBeanFactory#setAllowEagerClassLoading
  14. */
  15. protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
  16. // 如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性
  17. // 此属性的含义:是否允许覆盖同名称的不同定义的对象
  18. if (this.allowBeanDefinitionOverriding != null) {
  19. beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  20. }
  21. // 如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性
  22. // 此属性的含义:是否允许bean之间存在循环依赖
  23. if (this.allowCircularReferences != null) {
  24. beanFactory.setAllowCircularReferences(this.allowCircularReferences);
  25. }
  26. }

是否允许覆盖和允许依赖的设置这里这是判断了是否为空,如果不为空则进行设置,但是并没有看到在哪里进行设置,究竟这个设置是在哪里进行设置的呢?还是那句话,使用子类覆盖方法,例如:

  1. public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
  2.  
  3. ......
  4.  
  5. @Override
  6. protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
  7. super.setAllowBeanDefinitionOverriding(false);
  8. super.setAllowCircularReferences(false);
  9. super.customizeBeanFactory(beanFactory);
  10. }
  11. }

二、加载BeanDefinition

在第一步中提到了ClassPathXmlApplicationContext与XmlBeanFactory创建的对比,在实现配置文件的加载功能中除了我们在第一步中已经初始化的DefaultListableBeanFactory外,还需要XmlBeanDefinitionReader来读取XML,那么在这个步骤中首先要做的就是初始化XmlBeanDefinitionReader。

  1. /**
  2. * Loads the bean definitions via an XmlBeanDefinitionReader.
  3. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
  4. * @see #initBeanDefinitionReader
  5. * @see #loadBeanDefinitions
  6. */
  7. @Override
  8. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
  9. // Create a new XmlBeanDefinitionReader for the given BeanFactory.
  10. // 为指定beanFactory创建XmlBeanDefinitionReader
  11. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
  12.  
  13. // Configure the bean definition reader with this context's
  14. // resource loading environment.
  15. // 对beanDefinitionReader进行环境变量的设置
  16. beanDefinitionReader.setEnvironment(this.getEnvironment());
  17. beanDefinitionReader.setResourceLoader(this);
  18. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
  19.  
  20. // Allow a subclass to provide custom initialization of the reader,
  21. // then proceed with actually loading the bean definitions.
  22. // 对beanDefinitionReader进行设置,可以覆盖
  23. initBeanDefinitionReader(beanDefinitionReader);
  24. loadBeanDefinitions(beanDefinitionReader);
  25. }

在初始化了DefaultListableBeanFactory和XmlBeanDefinitionReader后就可以进行配置文件的读取了。

  1. /**
  2. * Load the bean definitions with the given XmlBeanDefinitionReader.
  3. * <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory}
  4. * method; hence this method is just supposed to load and/or register bean definitions.
  5. * @param reader the XmlBeanDefinitionReader to use
  6. * @throws BeansException in case of bean registration errors
  7. * @throws IOException if the required XML document isn't found
  8. * @see #refreshBeanFactory
  9. * @see #getConfigLocations
  10. * @see #getResources
  11. * @see #getResourcePatternResolver
  12. */
  13. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
  14. Resource[] configResources = getConfigResources();
  15. if (configResources != null) {
  16. reader.loadBeanDefinitions(configResources);
  17. }
  18. String[] configLocations = getConfigLocations();
  19. if (configLocations != null) {
  20. reader.loadBeanDefinitions(configLocations);
  21. }
  22. }

使用XmlBeanDefinitionReader的loadBeanDefinitions方法进行配置文件的加载注册相信大家已经不陌生,这完全就是开始BeanFactory的套路。因为在XmlBeanDefinitionReader中已经将之前初始化的DefaultListableBeanFactory注册进去了,所有XmlBeanDefinitionReader所读取的BeanDefinitionHolder都会注册到DefaultListableBeanFactory中,也就是经过此步骤,类型DefaultListableBeanFactory的变量beanFactory已经包含了所有解析好的配置。

Spring源码分析(二十一)加载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源码分析系列】加载Bean

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

  5. 五、spring源码阅读之ClassPathXmlApplicationContext加载beanFactory

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml&q ...

  6. 从SpringBoot源码分析 配置文件的加载原理和优先级

    本文从SpringBoot源码分析 配置文件的加载原理和配置文件的优先级     跟入源码之前,先提一个问题:   SpringBoot 既可以加载指定目录下的配置文件获取配置项,也可以通过启动参数( ...

  7. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  8. Spring源码分析(十一)bean的加载

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过前面的分析,我们终于结束了对XML配置文件的解析,接下来将会面临更大 ...

  9. 【MyBatis源码分析】Configuration加载(下篇)

    元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...

  10. ABP源码分析二十一:Feature

    Feature是什么?Feature就是对function的分类方法,其与function的关系就比如Role和User的关系一样. ABP中Feature具有以下属性: 其中最重要的属性是name, ...

随机推荐

  1. fontforge制作自定义字体及在手机上应用举例——张鑫旭

    一.看似无关紧要的事件背景 之所以花时间折腾fontforge这个软件,去制作什么自定义的字体是有原因滴. 之前提过,最近我抽空将公司的手机软件HTML5网页化.期间碰到这么一个问题,页面低栏上的电话 ...

  2. 注重结构、语义、用户体验的Tab选项卡

    效果如下图所示: HTML code: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &quo ...

  3. Unexpected token o in JSON at position 1 at JSON.parse (<anonymous>) SyntaxError: Unexpected token R in JSON at position 0 at JSON.parse (<anonymous>)

    这个问题在之前做项目时碰到过一次,当时按照网上的做法,去掉JSON.parse()这一层转换后就没有这个报错了,数据也能正常使用,就没多想,也没深究是什么原因.可是这次又碰到了,所以这次我必须要弄明白 ...

  4. sql中 设置区分大小写

    CI 指定不区分大小写,CS 指定区分大小写alter table 表名 alter column 字段 nvarchar(100) collate chinese_prc_cs_as --区分大小写 ...

  5. 拖拽进度条(SeekBar)

    拖拽进度条(SeekBar) 监听方法:setOnSeekBarChangeListener 监听器:SeekBar.OnSeekBarChangeListener 简单,直接上代码: 1.Activ ...

  6. Spring框架学习之概述

    一.什么是软件框架 打个比方就像建筑的混凝土框架,搭好了架子,工人只需要把墙填上. .特点: -半成品 -封装了特定的处理流程和控制逻辑 -成熟的,不断升级改造的软件 .框架和类库的区别 -框架一般是 ...

  7. 大数据量报表APPLET打印分页传输方案

     1 . 问题概述 当报表运算完成时,客户端经常需要调用润乾自带的runqianReport4Applet.jar来完成打印操作, 然而数据量比较大的时候,会导致无法加载完成,直至applet内存 ...

  8. 润乾在jetty应用服务器下的JNDI配置一

     一. 此处绑定的数据源是以 DBCP 为实现.首先必须将数据库驱动(这里用了MYSQL数据库)和DBCP所需要的 Jar 包复制到 Jetty 根目录的 lib 目录下.DBCP主要需要以下3个 ...

  9. maven 安装与配置最佳实践

    配置Maven环境变量 1.新建 maven home 环境变量      变量名:M2_HOME     变量值:D:\ProgramFiles\apache-maven-3.5.4       2 ...

  10. 我的blog第一天

    今天是2017年6月13号,一个很平凡的日子,但是对我来说意义非凡.这是我开通博客的第一天,这是我写的第一篇文章. 先自我介绍一下,本人邢卜,河北石家庄人,生于89年6月,说到这我马上就要过生日了!嘿 ...