• 加载BeanFactory


    前言

    上一篇文章讲述了ApplicationContext扩展功能的之一:环境准备。这篇文章接着讲述ApplicationContext的扩展功能-----加载BeanFactory,也就是初始化BeanFactory,并进行XML文件的读取。

    加载BeanFactory

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

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
            //初始化beanFactory,并进行XML文件的读取,并将得到的BeanFactory记录在当前实体的属性中
            refreshBeanFactory();
            //返回当前实体的BeanFactory属性
            return getBeanFactory();
        }
    protected final void refreshBeanFactory() throws BeansException {
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }
            try {
                //创建DefaultListableBeanFactory
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                //为了序列化指定ID,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
                beanFactory.setSerializationId(getId());
                //定制BeanFactory,设置相关的属性,包括是否覆盖同名称的不同定义的对象以及循环依赖以及设置@Autowire和@Qualifier注解解析器
                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("spring.xml");,其中的XMLBeanFactory继承自DefaultListableBeanFactory,并提供了XmlBeanDefinitionReader类型的reader属性,也就是说DefaultListableBeanFactory是容器的基础。必须要首先实例化,那么在这里就是实例化DefaultListableBeanFactory的步骤。

    (2)指定序列化id。

    (3)定制BeanFactory。

    (4)加载BeanDefinition。

    (5)使用全局变量记录BeanFactory类实例。

    因为DefaultListableBeanFactory类型的变量BeanFactory是函数类的局部变量,所以要使用全局变量记录解析结果。

    接下来对上述的一些步骤进行详细的解析:

    定制BeanFactory

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

    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 MyClassPathApplicationContext extends ClassPathXmlApplicationContext {
    
        @Override
        protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
            super.setAllowBeanDefinitionOverriding(false);
            super.setAllowCircularReferences(false);
            super.customizeBeanFactory(beanFactory);
        }
    }

     加载BeanDefinition

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

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            //为指定BeanFactory创建XmlBeanDefinitionReader
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
            // 对BeanDefinitionReader进行环境变量的设置
            beanDefinitionReader.setEnvironment(this.getEnvironment());
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
            //对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已经包含了所有解析好的配置。

     参考:《Spring源码深度解析》  郝佳 编著:

    作者:Joe
    努力了的才叫梦想,不努力的就是空想,努力并且坚持下去,毕竟这是我相信的力量
  • 相关阅读:
    linux运维、架构之路-K8s中部署Jenkins集群高可用
    linux运维、架构之路-K8s数据管理
    linux运维、架构之路-K8s通过Service访问Pod
    linux运维、架构之路-K8s应用
    linux运维、架构之路-K8s健康检查Health Check
    linux运维、架构之路-K8s滚动更新及回滚
    linux运维、架构之路-Kubernetes基础(一)
    Python前端HTML
    linux运维、架构之路-Kubernetes离线集群部署-无坑
    linux运维、架构之路-MongoDB单机部署
  • 原文地址:https://www.cnblogs.com/Joe-Go/p/10211289.html
Copyright © 2020-2023  润新知