美文网首页
Spring 4.3 源码分析之 IOC 高级容器启动

Spring 4.3 源码分析之 IOC 高级容器启动

作者: 爱吃鱼的KK | 来源:发表于2018-01-29 23:16 被阅读88次
    1. IOC 高级容器启动之猜测

    前篇叙述了基本IOC容器的启动, 这里针对的是高级IOC容器(ApplicationContext), 而 高级IOC容器 ApplicationContext中往往有个基本容器 DefaultListableBeanFactory(比如 AbstractRefreshableApplicationContext中的 beanFactory属性), 把高级容器与基本容器的区别主要归结如如下:

    1. 继承 DefaultResourceLoader, 本身就拥有 Resource 读取的能力(PS: 但一般都是使用 PathMatchingResourcePatternResolver, 这个类支持 ant 表达式匹配配置文件)
    2. 支持多种文件的获取配置文件 classPath, fileSystem, URL 等
    3. 统一注册 BeanFactoryPostProcessor, 以及统一进行激活
    4. 统一获取 BeanPostProcessor, 并进行注册
    5. 容器事件的监听器的添加 ApplicationContextListener
    6. 通过 DefaultListableBeanFactory.preInstantiateSingletons 来进行事先创建 Bean (DefaultListableBeanFactory默认是使用时才创建)
    
    2. IOC 高级容器使用 Demo

    这里我们还是用和前一篇相似的demo来进行叙述:

    <!-- XML 内容 org/springframework/beans/factory/xml/application.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
        <bean id="testBean" class="org.springframework.tests.sample.beans.TestBean" />
    </beans>
    
    // 测试代码
    public void testSingleConfigLocation() {
        String resourceName = "org/springframework/beans/factory/xml/application.xml";
        // 创建工厂
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourceName);
        // 获取对应的类 testBean
        TestBean bean = (TestBean) factory.getBean("testBean");
        assertNotNull(bean);
        ctx.close();
    }
    

    和上篇不同的一点, 是这里的主角换成了 ClassPathXmlApplicationContext

    3. IOC 高级容器启动之构造函数

    在这个函数中主要完成了:

    1. 设置资源匹配及获取器 PathMatchingResourcePatternResolver
    2. 设置配置文件的地址
    3. 调用 refresh() 方法来初始化整个容器
    
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        // 在父类中设置 自己的 ResourcePatternResolver = PathMatchingResourcePatternResolver
        super(parent);
        // 解析 Bean 定义资源文件的路径, 处理多个资源文件字符串数组
        setConfigLocations(configLocations);
        // refresh 默认 true
        if (refresh) { // refresh()才是正真的主逻辑
            refresh();
        }
    }
    
    4. IOC 高级容器核心方法 refresh() 概述

    毫不客气的说 refresh() 是 AbstractApplicationContext 里面的核心中的核心, 主要分成下面几步:

    1. prepareRefresh:                   准备刷新上下文环境 -> 调用的是 AbstractApplicationContext#refresh -> 设置容器启动的时间 -> 设置容器的激活状态 -> 将 servletContext, servletConfig 设置到 AbstractBeanFactory.StandardEnvironment.PropertySourcesPropertyResolver.propertySources 里面
    2. obtainFreshBeanFactory:           调用子类去创建 DefaultListableBeanFactory, 并且去加载配置文件中配置的 Bean 信息
    3. prepareBeanFactory:               为 BeanFactory 配置容器特性, 例如类加载器, 标准的 bean 表达式解析器, 属性编辑注册器, 时间处理器等
    4. postProcessBeanFactory:           主要是注册 request/session 类型的 scope, 与 ServletContextAwareProcessor
    5. invokeBeanFactoryPostProcessors:  实例化并激活所有的 注册到容器中的  BeanFactoryPostProcessor (这里分为针对实现接口 PriorityOrdered, Ordered, 与剩下的其他BeanFactoryPostProcessor分别处理.)
    6. registerBeanPostProcessors:       注册 Bean 的后主处理器, 这些后置处理器在 Bean 的创建过程中调用 (PS: getBean中)
    7. initMessageSource:                初始化 MessageSource(主要是完成 国际化处理), 如果 beanFactory 不存在此 bean 则采用默认的配置并社会父类 messageSource
    8. initApplicationEventMulticaster:  初始化 ApplicationEventMulticaster 事件, 默认使用 SimpleApplicationEventMulticaster 事件
    9. onRefresh:                        调用子类的某些特殊 Bean 初始化方法, 比如这里的 ThemeSource
    10. registerListeners:               在所有 Bean 中查找 ApplicationListener bean, 注册到消息广播器(SimpleApplicationEventMulticaster)中
    11. finishBeanFactoryInitialization: 初始化所有除 非单例/抽象类/lazyInit = true 的类; 这里调用 的是 BeanFactory 的 preInstantiateSingletons 这个方法是由 DefaultListableBeanFactory 实现的
    12. finishRefresh:                   完成刷新过程, 通知生命周期处理器,  lifecycleProcessor 刷新过程, 同时发出 ContextRefreshEvent 通知别人
    

    代码部分如下:

    /**
     * 参考资料:
     * http://www.cnblogs.com/ITtangtang/p/3978349.html
     */
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 准备刷新上下文环境 -> 调用的是 AbstractApplicationContext#refresh -> 设置容器启动的时间 -> 设置容器的激活状态 -> 将 servletContext, servletConfig 设置到 AbstractBeanFactory.StandardEnvironment.PropertySourcesPropertyResolver.propertySources 里面
            // Prepare this context for refreshing.
            prepareRefresh();
    
            // 调用子类去创建 DefaultListableBeanFactory, 并且去加载配置文件中配置的 Bean 信息
            // 调用的是 AbstractRefreshableApplicationContext#refreshBeanFactory -> AbstractRefreshableApplicationContext#getBeanFactory
            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
            // 为 BeanFactory 配置容器特性, 例如类加载器, 标准的 bean 表达式解析器, 属性编辑注册器, 时间处理器等
            // Prepare the bean factory for use in this context.
            // 调用的是 AbstractApplicationContext#prepareBeanFactory
            prepareBeanFactory(beanFactory);
    
            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 主要是注册 request/session 类型的 scope, 与 ServletContextAwareProcessor
                // 调用的是 AbstractRefreshableWebApplicationContext#postProcessBeanFactory
                postProcessBeanFactory(beanFactory);
    
                // 实例化并激活所有的 注册到容器中的  BeanFactoryPostProcessor (这里分为针对实现接口 PriorityOrdered, Ordered, 与剩下的其他BeanFactoryPostProcessor分别处理.)
                // Invoke factory processors registered as beans in the context.
                // 其实调用 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors (PS: 里面步骤很多, 但不复杂)
                invokeBeanFactoryPostProcessors(beanFactory);
    
                // 注册 Bean 的后主处理器, 这些后置处理器在 Bean 的创建过程中调用 (PS: getBean中)
                // 为 BeanFactory 注册 BeanPost 事件处理器
                // BeanPostProcessor 是 Bean 后置处理器, 用于监听容器触发的事件
                // Register bean processors that intercept bean creation.
                // 调用的是 PostProcessorRegistrationDelegate.registerBeanPostProcessors
                registerBeanPostProcessors(beanFactory);
    
                // 初始化 MessageSource(主要是完成 国际化处理), 如果 beanFactory 不存在此 bean 则采用默认的配置并社会父类 messageSource
                // Initialize message source for this context.
                initMessageSource();
    
                // Initialize event multicaster for this context.
                // 初始化 ApplicationEventMulticaster 事件, 默认使用 SimpleApplicationEventMulticaster 事件
                initApplicationEventMulticaster();
    
                // 调用子类的某些特殊 Bean 初始化方法, 比如这里的 ThemeSource
                // Initialize other special beans in specific context subclasses.
                // 其实调用的是 AbstractRefreshableWebApplicationContext.onRefresh
                onRefresh();
    
                // 在所有 Bean 中查找 ApplicationListener bean, 注册到消息广播器(SimpleApplicationEventMulticaster)中
                // Check for listener beans and register them.
                // 其实调用的是 AbstractApplicationContext#registerListeners
                registerListeners();
    
                // 初始化所有除 非单例/抽象类/lazyInit = true 的类
                // 这里调用 的是 BeanFactory 的 preInstantiateSingletons 这个方法是由 DefaultListableBeanFactory 实现的
                // Instantiate all remaining (non-lazy-init) singletons.
                // 调用的是 AbstractApplicationContext#finishBeanFactoryInitialization
                finishBeanFactoryInitialization(beanFactory);
    
                // 完成刷新过程, 通知生命周期处理器,  lifecycleProcessor 刷新过程, 同时发出 ContextRefreshEvent 通知别人
                // Last step: publish corresponding event.
                // 调用的是 AbstractApplicationContext#finishRefresh
                finishRefresh();
            }
    
            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }
    
                // Destroy already created singletons to avoid dangling resources.
                // 销毁已经创建的 Bean
                destroyBeans();
    
                // 取消  refresh 事件, 重置容器的同步标识
                // Reset 'active' flag.
                cancelRefresh(ex);
    
                // Propagate exception to caller.
                throw ex;
            }
    
            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }
    

    上面代码中展现了 AbstractApplicationContext 的创建主逻辑, 而关于bean创建那部分在前一篇里面有详细概述

    4. IOC 高级容器分类

    在使用 applicationContext 中, 主要使用如下几个类型:

    1. ClassPathXmlApplicationContext:   通过在构造函数中传入 classpath 下的配置文件地址来生成 ApplicationContext (PS: 这里是通过DefaultResourceLoader来进行获取配置文件)
    2. FileSystemXmlApplicationContext:  通过在构造函数中传入配置文件地址来生成 ApplicationContext (PS: 这里是通过PathMatchingResourcePatternResolver 来进行获取配置文件 <- 主要是通过 Ant 表达式获取所有 jar/war 包下满足条件的配置文件)
    3. XmlWebApplicationContext:         当在web.xml 里面配置 ContextLoaderListener 时会创建这个 applicationContext(PS: 配置DispatcherServlet时, 也会在构造函数中创建 XmlWebApplicationContext对象)
    4. AnnotationConfigWebApplicationContext: 基于一个配置Bean的基于注解的ApplicationContext
    
    5. 总结:

    本篇主要结构了 ApplicationContext 的整个启动过程 + 分类, 其实正真要理解 IOC 容器的话, 还是需要看看 Spring 4.3.x IOC 基本容器启动 这篇!

    6. 参考资料

    Spring技术内幕分析
    Spring IOC 原理
    Spring 5 源码分析
    开涛的 Spring杂谈
    伤神的 Spring源码分析
    Spring Core
    Spring IOC 源码分析
    Spring源码情操陶冶
    Spring 揭秘 (PS: 这本书绝对给力)
    Spring 技术内幕
    Spring 源码深度分析
    Spring 高级程序设计 (PS:这本书已经绝版, 所以当时是自己下载 pdf, 然后联系淘宝卖家忙帮复印, 其实就是英文版本的 "Pro Spring 3")
    深入分析 Java Web(PS: 许令波写的, 虽然是本老书, 但是里面分析得确实很深入)
    expert one-on-one J2EE Development without EJB (PS: Spring 作者自己写的书, 当时也是下载 PDF, 联系淘宝卖家复印购买到的)

    相关文章

      网友评论

          本文标题:Spring 4.3 源码分析之 IOC 高级容器启动

          本文链接:https://www.haomeiwen.com/subject/ebstzxtx.html