• 【Spring源码这样读】-再次走近容器Spring IOC 三


    上两篇,我们已经基本的分析完了XmlBeanFactory的应用实例,本章我们一起来分析一下ApplicationContext。大佬略过

    前两两篇已经将基本的XmlBeanFactory操作实例讲完了,这里我们来聊聊ApplicationContext。在之前也提过,这两个东西基本流程上应该是相差不多的。比如我们之前推测:

    • 读取配置文件
    • 根据配置文件找到对应的类并通过反射来实例化
    • 然后存入容器,被调用的时候取出

    ApplicationContext和XmlBeanFactory的区别

    在ApplicationContext的源码解析中,这些推测还能使用吗?答案是可以的。之前我们聊过IOC容器的设计与实现,无非就是两个系列,一个BeanFactory,一个ApplicationContext。那么我们之前看的XmlBeanFactory属于哪一种类呢?先来看一下XmlBeanFactory的类图
    在这里插入图片描述

    XmlBeanFactory继承体系是
    XmlBeanFactory -> DefaultListableBeanFactory -> AbstractAutowireCapableBeanFactory -> AbstractBeanFactory -> FactoryBeanRegistrySupport -> DefaultSingletonBeanRegistry -> SimpleAliasRegistry -> AliasRegistry

    但是请注意:XmlBeanFactory是在DefaultListableBeanFactory的基础上做扩展的。其实最终还是实现了BeanFactory接口。而我们的ApplicationContext,它是做为一种容器的高级形态存在。应用上下文,在简单的容器上增加了许多其他的特性。为什么这么说呢?我们来看看ApplicationContext的类图。

    在这里插入图片描述

    不难发现ApplicationContext其实也是实现了BeanFactory,但是这里可以明显的看到,ApplicationContext做了更多的支持。

    BeanFactory

    BeanFactory是Spring最核心的所在,很多面试题问Spring是什么?其实就可以直接回答:Spring其实就是一个BeanFactory的巨大封装,当然好像有点片面,BeanFactory确确实实是Spring最核心的内容。

    BeanFactory提供的是最基本的IOC容器的功能,关于这些功能,我们可以来读一下他的源码

    String FACTORY_BEAN_PREFIX = "&";
    
    /**
     * 根据名称获取bean
     */
    Object getBean(String name) throws BeansException;
    
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    
    <T> T getBean(Class<T> requiredType) throws BeansException;
    
    Object getBean(String name, Object... args) throws BeansException;
    
    /**
     * 是否包含bean
     */
    boolean containsBean(String name);
    
    /**
     * 查询bean是否是Singleton类型
     */
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    
    /**
     * 查询bean是否是Prototype类型
     */
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    
    /**
     * 查询bean的class类型是否是特定的class类型
     */
    boolean isTypeMatch(String name, Class<?> targetType)
            throws NoSuchBeanDefinitionException;
    
    /**
     * 查询bean的class类型
     */
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    
    /**
     * 查询bean的所有别名
     */
    String[] getAliases(String name);
    

    其实它的代码并不多,但是它提供了使用IOC容器的规范。理解这些呢,有助于我们理解ApplicationContext,我们可以直接认为BeanFactory是一种简单的容器形式,而ApplicationContext它是一种高级的容器形式。

    到这里,其实我们已经看到XmlBeanFactory和ApplicationContext的一些区别了。但是这里其实不是那么的明显。我们不妨再来看看那ApplicationContext它的实现类ClassPathXmlApplicationContext,也就是我们代码里面用的。它的一个源码和XmlBeanFactory的区别在哪

    ClassPathXmlApplicationContext

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();
        }
    }
    

    它的初始化在不断的调用super(parent),但是refresh()方法完成了容器的初始化。

    refresh()方法的实现代码如下

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh(); // 准备工作
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); // 获取ConfigurableListableBeanFactory最终的目的是DefaultListableBeanFactory
            this.prepareBeanFactory(beanFactory); // 准备bean工厂
    
            try {
                this.postProcessBeanFactory(beanFactory); // 一个空的实现,注意这里的spring版本号为:5.3x
                this.invokeBeanFactoryPostProcessors(beanFactory); // 注册bean的工厂
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource(); // Spring 从所有的 @Bean 定义中抽取出来了 BeanPostProcessor,然后都注册进 beanPostProcessors,等待后面的的顺序调用 注册BeanPostProcessor
                this.initApplicationEventMulticaster(); // 初始化事件监听多路广播器
                this.onRefresh(); // 一个空的实现
                this.registerListeners(); // 注册监听器
                this.finishBeanFactoryInitialization(beanFactory); // 到了spring加载流程最复杂的一步,开始实例化所有的bd
                this.finishRefresh();// 刷新完成工作
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
    
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }
    
        }
    }
    

    方法从总体上看 还算比较清晰 用几个大的方法高度概括了refresh()做了些什么。后面我们会详细来解读这些流程,这里仅做一个总结。

    到这里位置,我们看到了ClassPathXmlApplicationContext的一个流程,和我们的XmlBeanFactory的区别相当的大,在我们之前的推测中,他应该先去加载xml,其实这里也做了,只是隐藏的比较深,在这个加载流程的第二部的具体内容里面,我们这里贴一下核心代码

    ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
    
    this.refreshBeanFactory();
    
    this.loadBeanDefinitions(beanFactory);
    
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }
    

    其实bean的初始化和容器的初始化也在这个流程里面全部提现了,这个我们后面再讲,但是从我们总结的内容来看,其实和我们的推测是大差不差的,只是多了很多其他的东西而已。多出来的这些东西也正是我们两种容器实现的区别所在。

    总结:

    • BeanFactory的基本实现提供了基本的IOC容器,ApplicaitonContext以高级形态出现,增加了很多附加功能。
    • XmlBeanFactory是我们BeanFactory一种最基本应用
    • XmlBeanFactory和ClassPathXmlApplicationContext都具备我们推测的流程,但是实现有所不同,而且具体流程上,两个区别很大
  • 相关阅读:
    模态对话框
    js小练习题
    js练习题
    python实现不同格式九九乘法表
    Python学习笔记之疑问12:什么是tuple
    Python学习笔记之疑问11:批量赋值
    Python学习笔记之疑问10:如何使用分隔符连接list中的字符串
    Python学习笔记之疑问 9:如何使用For语句
    Python学习笔记之疑问 8:Python 中的问号表达式
    Python学习笔记之疑问 7:自定义模块放在什么位置
  • 原文地址:https://www.cnblogs.com/xlecho/p/14673008.html
Copyright © 2020-2023  润新知