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

目录

一、定制化BeanFactory

二、加载BeanDefinition

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

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

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

/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 为了序列话指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
beanFactory.setSerializationId(getId());
/**
* 设置两个属性:
* 1. 是否允许覆盖同名称的不同定义的对象
* 2. 是否允许bean之间存在循环依赖
*/
customizeBeanFactory(beanFactory);
// 初始化DocumentReader,并进行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。

在介绍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的扩展,在基本容器的基础上,增加了是否允许覆盖是否允许扩展的设置。

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

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

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

    ......

    @Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.setAllowBeanDefinitionOverriding(false);
super.setAllowCircularReferences(false);
super.customizeBeanFactory(beanFactory);
}
}

二、加载BeanDefinition

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

/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #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进行环境变量的设置
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.
// 对beanDefinitionReader进行设置,可以覆盖
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}

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

/**
* Load the bean definitions with the given XmlBeanDefinitionReader.
* <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory}
* method; hence this method is just supposed to load and/or register bean definitions.
* @param reader the XmlBeanDefinitionReader to use
* @throws BeansException in case of bean registration errors
* @throws IOException if the required XML document isn't found
* @see #refreshBeanFactory
* @see #getConfigLocations
* @see #getResources
* @see #getResourcePatternResolver
*/
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);
}
}

使用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. 自定义TableViewCell 的方式实现自定义TableView(带源码)

    转载于:http://www.cnblogs.com/macroxu-1982/archive/2012/08/30/2664121.html 实现的效果 实现过程 Step One 创建 自定义Ta ...

  2. MySQL创建数据库/表等基本命令操作

    前提:安装好MySQL并且配置好服务,能够正常使用 按住键盘上的Windows图标,通过搜索框找到MySQL5.7 Command Line Client,点击启动 输入安装时设置用户的密码 成功连接 ...

  3. 使用WebDAV实现Office文档在线编辑

    Office的文档处理能力是非常强大的,但是它是本地资源,在Office Web App尚未成熟前,仍需要使用本地能力来进行文档编辑,可是现代的系统的主流却是B/S,所以在B/S中调用本地的Offic ...

  4. Java 之常用API(二)

    Object类 & System类 日期相关类 包装类 & 正则表达式 Object类 & System类 1.1 Object类 1.1.1 概述 Object类是Java语 ...

  5. linux 搜索文件内容并输出命令 grep、-i、-v ^#

    grep /bin/grepgrep -iv [指定字条串] [文件]在文件中搜索字符串匹配的行并输出-i 不区分大小写 -v 排除指定字符串 grep -i java /etc/profile gr ...

  6. jsp到java后台中文乱码问题

    ---首先描述一下我的情况,我的jsp    设置了编码格式 <%@ page language="java" contentType="text/html; ch ...

  7. linux之redis

    配置环境变量的命令: 修改环境变量: vim /root/.bash_profile 添加以下配置: export PATH=/server/tools/redis/src:$PATH 激活环境变量 ...

  8. shell_processing

    1.文本处理_2:grep,sed,awk 2.regular_expression 3.Test   一.文本处理_2 1.grep --Linux处理正则表达式的主要程序.正则表达式是一种符号表示 ...

  9. [SQL Server]SQL行转列

    SELECT * FROM (select ActionTargetType+actiontype as TypeResult, COUNT(RowGuid) as Number from BanJi ...

  10. 转:tomcat安全设置

      小程序部署上去后,用户反馈说存在注入入侵等风险.反省之,记录下来 最省事的办法,直接删除%tomcatRoot%/webapps下的所有文件夹,仅仅保留自己部署的工程 前提是你不需要监控程序的一些 ...