Spring源码分析(二十一)加载BeanFactory
摘要: 本文结合《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的更多相关文章
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
- 【Spring源码分析】Bean加载流程概览(转)
转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...
- Spring源码分析:Bean加载流程概览及配置文件读取
很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...
- 【Spring源码分析系列】加载Bean
/** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * ...
- 五、spring源码阅读之ClassPathXmlApplicationContext加载beanFactory
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml&q ...
- 从SpringBoot源码分析 配置文件的加载原理和优先级
本文从SpringBoot源码分析 配置文件的加载原理和配置文件的优先级 跟入源码之前,先提一个问题: SpringBoot 既可以加载指定目录下的配置文件获取配置项,也可以通过启动参数( ...
- spring源码分析(二)Aop
创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...
- Spring源码分析(十一)bean的加载
摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过前面的分析,我们终于结束了对XML配置文件的解析,接下来将会面临更大 ...
- 【MyBatis源码分析】Configuration加载(下篇)
元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...
- ABP源码分析二十一:Feature
Feature是什么?Feature就是对function的分类方法,其与function的关系就比如Role和User的关系一样. ABP中Feature具有以下属性: 其中最重要的属性是name, ...
随机推荐
- fontforge制作自定义字体及在手机上应用举例——张鑫旭
一.看似无关紧要的事件背景 之所以花时间折腾fontforge这个软件,去制作什么自定义的字体是有原因滴. 之前提过,最近我抽空将公司的手机软件HTML5网页化.期间碰到这么一个问题,页面低栏上的电话 ...
- 注重结构、语义、用户体验的Tab选项卡
效果如下图所示: HTML code: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &quo ...
- 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()这一层转换后就没有这个报错了,数据也能正常使用,就没多想,也没深究是什么原因.可是这次又碰到了,所以这次我必须要弄明白 ...
- sql中 设置区分大小写
CI 指定不区分大小写,CS 指定区分大小写alter table 表名 alter column 字段 nvarchar(100) collate chinese_prc_cs_as --区分大小写 ...
- 拖拽进度条(SeekBar)
拖拽进度条(SeekBar) 监听方法:setOnSeekBarChangeListener 监听器:SeekBar.OnSeekBarChangeListener 简单,直接上代码: 1.Activ ...
- Spring框架学习之概述
一.什么是软件框架 打个比方就像建筑的混凝土框架,搭好了架子,工人只需要把墙填上. .特点: -半成品 -封装了特定的处理流程和控制逻辑 -成熟的,不断升级改造的软件 .框架和类库的区别 -框架一般是 ...
- 大数据量报表APPLET打印分页传输方案
1 . 问题概述 当报表运算完成时,客户端经常需要调用润乾自带的runqianReport4Applet.jar来完成打印操作, 然而数据量比较大的时候,会导致无法加载完成,直至applet内存 ...
- 润乾在jetty应用服务器下的JNDI配置一
一. 此处绑定的数据源是以 DBCP 为实现.首先必须将数据库驱动(这里用了MYSQL数据库)和DBCP所需要的 Jar 包复制到 Jetty 根目录的 lib 目录下.DBCP主要需要以下3个 ...
- maven 安装与配置最佳实践
配置Maven环境变量 1.新建 maven home 环境变量 变量名:M2_HOME 变量值:D:\ProgramFiles\apache-maven-3.5.4 2 ...
- 我的blog第一天
今天是2017年6月13号,一个很平凡的日子,但是对我来说意义非凡.这是我开通博客的第一天,这是我写的第一篇文章. 先自我介绍一下,本人邢卜,河北石家庄人,生于89年6月,说到这我马上就要过生日了!嘿 ...