zoukankan      html  css  js  c++  java
  • 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已经包含了所有解析好的配置。

  • 相关阅读:
    MD5算法MFC实现
    asp.net2.0新特点
    file format
    C专家编程第二章学习笔记
    Bye Czech golden generation
    中间层
    学完谭C之后
    C语言学习之路
    荀子劝学篇
    C语言常用转义字符表
  • 原文地址:https://www.cnblogs.com/warehouse/p/9385110.html
Copyright © 2011-2022 走看看