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

2018-01-29  本文已影响88人  爱吃鱼的KK
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, 联系淘宝卖家复印购买到的)

上一篇下一篇

猜你喜欢

热点阅读