Spring IOC refresh()方法——加载BeanFactory

原创 2018年04月16日 17:43:34

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

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

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

@Override
protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 创建DefaultListableBeanFactory 
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
        beanFactory.setSerializationId(getId());
        // 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象和循环依赖
        // 以及设置@Autowired 和 @Qualifier 注解解析器 QualifierAnnotationAutowire CandidateResolver 
        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 bf = new XmlBeanFactory(“applicationContext.xml”),其中的XmlBeanFactory继承自DafaultListableBeanFactory,并提供了XmlBeanDefinitionReader类型的reader属性,也就是说DafaultListableBeanFactory是容器的基础。必须首先要实例化,那么在这里就是实例化DefaultListableBeanFactory 的步骤。
(2)指定序列化ID。
(3)定制BeanFactory。
(4)加载BeanDefinition。
(5)使用全局变量记录BeanFactory类实例。
因为DefaultListableBeanFactory 类型的变量beanFactory是函数内的局部变量,所以要使用全局变量记录解析结果。

定制BeanFactory
这里已经开始对BeanFactory的扩展,在基本容器的基础上,增加了是否允许覆盖,是否允许扩展的设置并提供了注解@Qualifier 和 @Autowired的支持。

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);
    }
    //用于@Qualifier 和 @Autowired
    beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
}

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

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{

    public MyClassPathXmlApplicationContext(String... configLocations) {
        super(configLocations);
    }

    @Override
    protected void initPropertySources() {
        //super.initPropertySources();
        getEnvironment().getRequiredProperty("VAR");
    }

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

}

设置完后相信已经对于这两个属性的使用有所了解了,对于定制BeanFactory,Spring还提供了另外一个重要的扩展,就是设置AutowrieCandidateResolver,而对于默认的实现并没有过多的逻辑处理。在这里,Spring使用了QualifierAnnotationAutowiredCandidateResolver,设置了这个解析器后Spring就可以支持注解方式的注入了。

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

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    // 创建XmlBeanDefinitionReader指定给beanFactory
    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后就可以进行配置文件的读取了。

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已经包含了所有解析好的配置。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yp1125/article/details/79963846

Spring ioc容器启动流程—obtainFreshBeanFactory

本文以XmlWebApplicationContext启动为例说明spring ioc容器启动流程。         obtainFreshBeanFactory的主要工作是创建DefaultList...
  • Architect0719
  • Architect0719
  • 2016-11-09 15:52:05
  • 1509

spring初始化refresh()方法中obtainFreshBeanFactory()源码走读。

简述obtainFreshBeanFactory()方法: 分析ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactor...
  • jy0902
  • jy0902
  • 2016-01-14 17:19:35
  • 1494

Spring原理(一)IoC容器的初始化过程之BeanFactory

IoC容器的初始化过程 IoC容器的启动过程包括BeanDefinition的Resource定位、载入和注册三个基本过程。 但spring是把这三个过程分开的,并用不同的模块来完...
  • wutian713
  • wutian713
  • 2016-09-22 19:17:36
  • 1051

spring ioc设计之BeanFactory接口系统解析

1.从接口BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,是一条主要的BeanFactory设计路径,在这条接口设计陆军 ...
  • ElephantBoy
  • ElephantBoy
  • 2016-10-17 11:16:03
  • 308

【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)

最基本的IoC容器-BeanFactory
  • jiuqiyuliang
  • jiuqiyuliang
  • 2015-02-16 16:42:56
  • 8965

Spring IOC 源码-ClassPathXmlApplicationContext-bean解析

1、使用方式-使用ApplicationContext方式加载XML @Test     public void testBeanLoader(){         BeanFactory bf = ...
  • xiaoxiaoxuanao
  • xiaoxiaoxuanao
  • 2016-09-18 13:58:47
  • 405

maven项目-加载不到spring文件,BeanFactory not initialized or already closed - call 'refresh' bef

严重: Exception sending context initialized event to listener instance of class org.springframework.we...
  • u014799292
  • u014799292
  • 2016-11-12 22:33:01
  • 4080

做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析之一

经过上面几节的简单介绍我们了解了spring的一些组件,现在我们来分析一下AbstractApplicationContext中的refresh()这个核心方法吧~ 用我们上一节的代码,debug...
  • linuu
  • linuu
  • 2016-03-12 14:21:38
  • 3174

Spring IOC-BeanFactory的继承体系结构

本文主要介绍BeanFactory以及它的各种继承层级的接口、抽象类及实现类,因为内容很多,所以这里不介绍ApplicationContext继承体系下的类(虽然ApplicationContext本...
  • chenzitaojay
  • chenzitaojay
  • 2015-07-01 22:41:44
  • 1630

Spring的refresh()方法调用过程

Spring的refresh()方法调用过程refresh()是Spring中比较核心的方法,Spring所有的初始化都在这个方法中完成具体代码如下public void refresh() thro...
  • who246
  • who246
  • 2017-02-05 22:05:21
  • 1924
收藏助手
不良信息举报
您举报文章:Spring IOC refresh()方法——加载BeanFactory
举报原因:
原因补充:

(最多只允许输入30个字)