SpringBoot 启动分析(五) — 上下文的刷新过程

1. SpringApplication.refreshContext

首先来看 SpringApplication 里刷新上下文的逻辑:

private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        } catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}

protected void refresh(ApplicationContext applicationContext) {
    Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    ((AbstractApplicationContext) applicationContext).refresh();
}

刷新的逻辑是在 AbstractApplicationContext.refresh 方法完成的,刷新完后注册了 JVM 的关闭回调钩子。

2. AbstractApplicationContext.refresh

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();

        // 让子类提供要刷新的 BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // 核心逻辑:调用上下文里以Bean形式注册的所有 BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 核心逻辑:向beanFactory注册 BeanPostProcessor,
            // 用于在创建 bean 时回调,以增强 bean
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 初始化 MessageSource
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            // 核心逻辑:实例化所有非延迟初始化的单例
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            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.
            destroyBeans();

            // 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();
        }
    }
}

上下文刷新的核心逻辑在于:
1、 调用上下文里以 Bean 形式注册的所有 BeanFactoryPostProcessor。

对于 AnnotationConfigEmbeddedWebApplicationContextAnnotationConfigApplicationContext 上下文,它们在构建的时候会创建 AnnotatedBeanDefinitionReaderAnnotatedBeanDefinitionReader在构造函数里会往上下文里注册一些基础组件,很重要的一个是ConfigurationClassPostProcessor,会在这里被调用,用于解析配置类、加载bean定义等。其他的具体见 AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Object source) 方法。

2、 向 beanFactory 注册 BeanPostProcessor,以这些 BeanPostProcessor 被应用的顺序注册的:

  • 不同组件的实现有如下三类分类
    1. 实现 PriorityOrdered 接口
    2. 实现 Ordered 接口
    3. 非继承上述两个接口的

  • 执行顺序规则
    1. PriorityOrdered -> Ordered -> 非继承上述接口的
    2. 同一类实现的 order 值越低优先级越高

3、 实例化所有非延迟初始化的单例。

4、如果刷新的过程出现 BeansException 异常则销毁已创建的 bean、把上下文标记为未激活。

5、最终清理缓存。

实例化前的准备工作

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 如果beanfactory里注册有ConversionService则使用
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // 如果需要,添加一个EmbeddedValueResolver,主要用于处理注解属性的值(${})
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
            @Override
            public String resolveStringValue(String strVal) {
                return getEnvironment().resolvePlaceholders(strVal);
            }
        });
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    // 冻结配置,使所有 bean 定义的元数据不再变化,从而可以缓存这些
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    // 实例化剩余所有非延迟加载的单例
    beanFactory.preInstantiateSingletons();
}

实例化 bean 之前的主要工作:
1. 指定 bean 类型转换类 ConversionService;
2. 准备一个 EmbeddedValueResolver 用于处理注解里的值(#{}/ ${});
3. 冻结配置,使 bean 定义不再变化,从而可以缓存它的的元数据。


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据