Spring 源码解析 | 容器初始化 refresh() 分析

 2023-02-14
原文作者:心城以北 原文地址:https://juejin.cn/post/7012639598262091784

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言:本文主要是讲 Spring 容器的启动过程主要是以题干的方式进行可能不回涉及过多的细节,希望大家阅读本文能对 Spring 容器初始化过程有一个简单的了解。 环境介绍:

  • Spring 5.3.10
  • Jdk 11

创建 Spring 容器

我们创建 Spring 容器可以通过一行代码进行创建

    AnnotationConfigApplicationContext applicationContext = 
        new AnnotationConfigApplicationContext(AppConfig.class);

在这个过程中核心就是调用 AnnotationConfigApplicationContext 的构造方法

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        this();
        register(componentClasses);
        // 刷新上下文
        refresh();
    }

Spring 容器创建过程 refresh 方法分析

Spring 容器创建过程主要就是调用 refresh() 方法。我们先一起看看 refresh() 方法具体做了哪些事。具体分为一下几个步骤:

  1. prepareRefresh 预刷新方法,主要是用来初始化和读取上下文配置信息;
  2. obtainFreshBeanFactory() 创建 BeanFactory 对象,其实就是创建一个 Bean 工厂;
  3. prepareBeanFactory(beanFactory) 配置 Bean 工厂,比如设置 ClassLoader、BeanPostProcessor 等;
  4. postProcessBeanFactory 允许子类进行拓展;
  5. invokeBeanFactoryPostProcessors 实例化并调用所有已注册的 BeanFactoryPostProcessor 。调用 BeanFactoryPostProcessor 需要按照顺序调用,优先级是a. 实现 _PriorityOrdered_ 接口;b. 实现 Order 接口; c. 默认。
  6. registerBeanPostProcessors 注册 Bean 对象的 BeanPostProcessors
  7. initMessageSource 初始化 messageSource 其实就是为了支持国际化;
  8. initApplicationEventMulticaster 初始化事件发布器;
  9. onRefresh 模板方法,可以给子类实现,以完成特殊的处理
  10. registerListeners 注册事件监听器,Spring 中的事件机制,其实就是一个典型的观察者模式,这里其实就是注册观察者。
  11. finishBeanFactoryInitialization 完成初始化单实例的非懒加载的 Bean 对象, 这里非常关键,对于 Bean 的初始化,属性填充,Aop 等都可以跟着这个方法找到。
  12. finishRefresh完成初始化,这里会发布一个 ContextRefreshedEvent 容器初始化完成事件,以及做一些其他的处理。

对这个过程我们又一个大概的了解过后,我们再来看看 refresh() 方法的定义:

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
    
            // Prepare this context for refreshing.
            prepareRefresh();
    
            // Tell the subclass to refresh the internal bean factory.
            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);
    
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);
    
                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
    
                // Initialize message source for this context.
                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();
                contextRefresh.end();
            }
        }
    }

参考文档