ApplicationContext(三)BeanFactory 初始化

ApplicationContext(三)BeanFactory 初始化

上节我们提到容器初始化的第一步首先进行了属性的检验,下面就要开始第二步:进行 beanFactory 的初始化工作了。

ApplicationContext 是对 BeanFactory 的功能上的扩展,不但包含了 BeanFactory 的全部功能更在其基础上添加了大量的扩展应用,那么 obtainFreshBeanFactory 正是实现 BeanFactory ,并对配置文件进行解析。

源代码【AbstractApplicationContext】

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 初始化 BeanFactory,并进行 XML 文件读取,并将得到的 BeanFactory 记录在当前实体的属性中
    refreshBeanFactory();
    // 返回当前实体的 BeanFactory 属性
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    return beanFactory;
}

很明显这段代码没有做什么事,将其主要的工作都委托给了 refreshBeanFactory() 方法,这个方法由其子类实现。

源代码【AbstractRefreshableApplicationContext】

protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 1. 创建 DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();

        // 为了序列化指定id,如果需要的话,让这个 beanFactory 从 id 反序列化到 BeanFactory 对象
        beanFactory.setSerializationId(getId());
        // 2. 定制 beanFactory,如设置:①是否允许同名覆盖、②是否允许循环依赖
        customizeBeanFactory(beanFactory);
        // 3. 初始化 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);
    }
}

在 refreshBeanFactory() 方法中主要做了三件事:

(1) 创建 BeanFactory。创建前需要先销毁以前的 beanFactory。

(2) 定制 BeanFactory。设置了是否允许同名覆盖、是否允许循环依赖两个属性。你可能会奇怪,这两个属性本来就是 null,没有值,这是在干什么?还是那名话,需要子类来覆盖。

(3) 加载 BeanFactory 配置文件。解析 xml 文件,加载 BeanDefinition。

一、创建 BeanFactory

protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

二、定制 BeanFactory

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    if (this.allowBeanDefinitionOverriding != null) {
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    if (this.allowCircularReferences != null) {
        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
}

三、加载 BeanDefinition

源代码【AbstractXmlApplicationContext】

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // 1. 创建 XmlBeanDefinitionReader
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // 2. 对 beanDefinitionReader 进行环境变量的设置
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // 3. 对 beanDefinitionReader 进行设置,默认可以覆盖
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
    reader.setValidating(this.validating);
}

在初始化了 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 中。

此时的 BeanFactory 已经解析了所有的 BeanDefinition,可以进行 bean 的加载了,不过在加载前 Spring 还做了一些其它的工作。


每天用心记录一点点。内容也许不重要,但习惯很重要!

posted on 2019-02-23 17:38  binarylei  阅读(532)  评论(0编辑  收藏  举报

导航