SpringBoot源码解读与原理分析(十三)IOC容器的启动流程

文章目录

    • 3.7 IOC容器的启动流程
      • 1.prepareRefresh——初始化前的预处理
      • 2.obtainFreshBeanFactory——初始化BeanFactory
      • 3.prepareBeanFactory——BeanFactory的预处理动作
      • 4.postProcessBeanFactory——BeanFactory的后置处理
      • 5.invokeBeanFactoryPostProcessors——执行BeanFactoryPostProcessors
      • 6.registerBeanPostProcessors——初始化BeanPostProcessor
      • 7.initMessageSource——初始化国际化组件
      • 8.initApplicationEventMulticaster——初始化事件广播器
      • 9.onRefresh——子类扩展的刷新动作
      • 10.registerListeners——注册监听器
      • 11.finishBeanFactoryInitialization——初始化剩余的单实例bean对象
      • 12.finishRefresh——刷新后的动作
      • 13.resetCommonCaches——清除缓存
    • 3.8 小结

3.7 IOC容器的启动流程

在 SpringBoot源码解读与原理分析(八)ApplicationContext 中,梳理了是ApplicationContext的几个重要实现类,其中AbstractApplicationContext显得尤为重要:

SpringBoot源码解读与原理分析(十三)IOC容器的启动流程_第1张图片

ApplicationContext的启动,其内部的核心动作的刷新容器,也就是AbstractApplicationContext中的refresh()方法。

AbstractApplicationContext.java

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        // 1.初始化前的预处理
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        // 2.获取BeanFactory,加载所有bean的定义信息(未实例化)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 3.BeanFactory的预处理配置
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 4.准备BeanFactory完成后进行的后置处理
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // 5.执行BeanFactory创建后的后置处理器
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 6.注册Bean的后置处理器
            registerBeanPostProcessors(beanFactory);

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

            // Initialize event multicaster for this context.
            // 8.初始化事件广播器
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 9.子类的多态onRefresh
            onRefresh();

            // Check for listener beans and register them.
            // 10.注册监听器
            registerListeners();

            // 至此,BeanFactory创建完成

            // Instantiate all remaining (non-lazy-init) singletons.
            // 11.初始化所有剩下的单实例
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 12.完成容器的创建工作
            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...
            // 13.清理缓存
            resetCommonCaches();
        }
    }
}

整个refresh方法分为13步,这篇文章只是梳理每一步都做了哪些事情,对于其中的细节设计放到之后的文章再展开。

1.prepareRefresh——初始化前的预处理

/**
 * Prepare this context for refreshing, setting its startup date and
 * active flag as well as performing any initialization of property sources.
 */
protected void prepareRefresh() {
    // Switch to active.
    // 切换IOC容器启动状态
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    if (logger.isDebugEnabled()) {
        if (logger.isTraceEnabled()) {
            logger.trace("Refreshing " + this);
        } else {
            logger.debug("Refreshing " + getDisplayName());
        }
    }

    // Initialize any placeholder property sources in the context environment.
    // 在上下文环境中初始化任何占位符属性源
    initPropertySources();

    // Validate that all properties marked as required are resolvable:
    // see ConfigurablePropertyResolver#setRequiredProperties
    // 验证标记为required的所有属性都是可解析的
    getEnvironment().validateRequiredProperties();

    // Store pre-refresh ApplicationListeners...
    // 存储预刷新的ApplicationListeners
    if (this.earlyApplicationListeners == null) {
        this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
    } else {
        // Reset local application listeners to pre-refresh state.
        // 将本地应用程序监听器重置为预刷新状态。
        this.applicationListeners.clear();
        this.applicationListeners.addAll(this.earlyApplicationListeners);
    }

    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    // 收集早期ApplicationEvents
    this.earlyApplicationEvents = new LinkedHashSet<>();
}

这一步骤大多数的动作都是前置性准备,包括切换IOC容器启动状态、初始化属性配置、属性检验、早期事件容器准备等。

2.obtainFreshBeanFactory——初始化BeanFactory

AbstractApplicationContext.java

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

这一步骤的refreshBeanFactory方法是一个抽象方法,由子类实现。不同的实现行为也不同。

(1)基于注解配置类的落地实现:GenericApplicationContext

GenericApplicationContext.java

@Override
protected final void refreshBeanFactory() throws IllegalStateException {
    if (!this.refreshed.compareAndSet(false, true)) {
        throw new IllegalStateException(
            "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    }
    this.beanFactory.setSerializationId(getId());
}

GenericApplicationContext的refreshBeanFactory方法中有一个CSA判断动作,控制着GenericApplicationContext不能反复刷新

(2)基于XML配置文件的落地实现:AbstractRefreshableApplicationContext

从类名可知,这是可刷新的ApplicationContext。该类的refreshBeanFactory方法会解析XML配置文件,封装BeanDefinition注册到BeanDefinitionRegistry中。

3.prepareBeanFactory——BeanFactory的预处理动作

AbstractApplicationContext.java

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // Tell the internal bean factory to use the context's class loader etc.
    // 注册类加载器、表达式解析器等
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // Configure the bean factory with context callbacks.
    // 编程式注册ApplicationContextAwareProcessor
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // BeanFactory interface not registered as resolvable type in a plain factory.
    // MessageSource registered (and found for autowiring) as a bean.
    // 绑定BeanFactory和ApplicationContext的依赖注入映射
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // Register early post-processor for detecting inner beans as ApplicationListeners.
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register default environment beans.
    // 注册Environment抽象
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

这一步骤的内部处理内容比较多,主要包含三件事情:

  • 设置一些默认组件(类加载器、表达式解析器等),注册Environment抽象(Environment也是IOC容器中的一个Bean);
  • 编程式注册ApplicationContextAwareProcessor,它负责支持6个Aware回调注入接口,包括EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware在内的6个接口;
  • 绑定BeanFactory和ApplicationContext的依赖注入映射。

4.postProcessBeanFactory——BeanFactory的后置处理

AbstractApplicationContext.java

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}

这一步骤的方法本身是一个模板方法,由子类具体实现。

(1)基于Web环境的实现:GenericWebApplicationContext

GenericWebApplicationContext.java

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    if (this.servletContext != null) {
        // 编程式注册ServletContextAwareProcessor
        beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    }
    // 注册新的Bean的作用域
    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    // 注册ServletContext
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
}

基于Web环境的实现GenericWebApplicationContext的postProcessBeanFactory方法做了3件事情:

  • 编程式注册ServletContextAwareProcessor,用于支持ServletContext的回调注入;
  • 注册新的Bean的作用域(request、session、application),并关联绑定ServletRequest、ServletResponse等多个类型的依赖注入映射;
  • 注册ServletContext、ServletConfig对象到IOC容器。

(2)基于嵌入式Web容器的实现:ServletWebServerApplicationContext

ServletWebServerApplicationContext.java

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    registerWebApplicationScopes();
}

这种方式是SpringBoot主要使用的,与基于Web环境的实现GenericWebApplicationContext相比,主要区别有:

  • registerWebApplicationScopes方法注册新的Bean的作用域时没有传参数,也就是没有注册作用域,因为此时嵌入式Web容器还没有完成初始化,没有ServletContext可以获取;
  • 没有注册ServletContext,理由同上。

5.invokeBeanFactoryPostProcessors——执行BeanFactoryPostProcessors

PostProcessorRegistrationDelegate.java

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    // 执行所有的BeanDefinitionRegistryPostProcessor
    Set<String> processedBeans = new HashSet<>();
    if (beanFactory instanceof BeanDefinitionRegistry) {
    
    // ...
    
    // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
    // 执行所有的BeanFactoryPostProcessor
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    
    //...
}

这一步骤会回调执行所有的BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor。在 SpringBoot源码解读与原理分析(十二)后置处理器 中详细梳理了这两个后置处理器的作用:

  • BeanDefinitionRegistryPostProcessor会对BeanDefinitionRegistry中存放的BeanDefinition进行处理(注册新的或移除现有的BeanDefinition);
  • BeanFactoryPostProcessor会对BeanDefinitionRegistry中存放的BeanDefinition进行修改操作(只限于修改,而不能新增或移除BeanDefinition),它的执行时机比BeanDefinitionRegistryPostProcessor更晚。

6.registerBeanPostProcessors——初始化BeanPostProcessor

PostProcessorRegistrationDelegate.java

public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    // 初始化所有的BeanPostProcessor
    // ...
}

这一步骤会初始化所有的BeanPostProcessor。

在 SpringBoot源码解读与原理分析(十二)后置处理器 中详细梳理了BeanPostProcessor的作用:它可以干预bean对象的实例化、初始化逻辑,postProcessBeforeInitialization在bean对象的初始化逻辑之前执行,postProcessAfterInitialization在初始化逻辑之后执行。另外postProcessAfterInitialization还可以对FactoryBean创建出的真实对象进行后置处理。

当前步骤初始化BeanPostProcessor时,由于容器中还没有初始化任何业务相关的bean对象,所以后续初始化的所有bean对象都会经过BeanPostProcessor的干预。

7.initMessageSource——初始化国际化组件

AbstractApplicationContext.java

protected void initMessageSource() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
        this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
        // Make MessageSource aware of parent MessageSource.
        // ...
        if (logger.isTraceEnabled()) {
            logger.trace("Using MessageSource [" + this.messageSource + "]");
        }
    } else {
        // Use empty MessageSource to be able to accept getMessage calls.
        // 未作配置时使用空的MessageSource
        DelegatingMessageSource dms = new DelegatingMessageSource();
        // ...
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
        }
    }
}

这一步骤会初始化默认的国际化组件,但默认的实现类DelegatingMessageSource在不作任何附加配置时不会处理任何国际化的工作,只有手动向IOC容器注册具体的国际化组件,应用上下文才具备国际化的能力。

8.initApplicationEventMulticaster——初始化事件广播器

AbstractApplicationContext.java

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        // 如果手动配置了ApplicationEventMulticaster,则使用配置的
        this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    } else {
        // 如果没有配置,则使用SimpleApplicationEventMulticaster
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " + "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
        }
    }
}

这一步骤会初始化ApplicationEventMulticaster,如果没有手动注册,则使用默认的简单实现SimpleApplicationEventMulticaster。

9.onRefresh——子类扩展的刷新动作

AbstractApplicationContext.java

protected void onRefresh() throws BeansException {
    // For subclasses: do nothing by default.
}

这是一个模板方法,默认没有任何实现。

借助IDEA可以查找到实现了该方法的类:

SpringBoot源码解读与原理分析(十三)IOC容器的启动流程_第2张图片
ReactiveWebServerApplicationContext中的扩展用于初始化基于Reactive环境的Web容器,ServletWebServerApplicationContext中的扩展用于初始化基于Servlet环境的Web容器。

10.registerListeners——注册监听器

AbstractApplicationContext.java

protected void registerListeners() {
    // Register statically specified listeners first.
    // 注册静态指定的监听器
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }
    
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    // 只绑定baenName而不直接取出监听器的原因:不让所有常规bean对象初始化
    // 后置处理器才能有机会干预
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }
    
    // Publish early application events now that we finally have a multicaster...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

这一步骤讲BeanDefinitionRegistry中注册的所有监听器(ApplicationListener)的beanName取出,绑定到事件广播器(ApplicationEventMulticaster)中。只绑定beanName而不直接取出监听器的原因是,考虑到ApplicationListener作为IOC容器中的Bean,应该和其他常规Bean放在一起统一创建和初始化,以让后置处理器有机会干预它们。

11.finishBeanFactoryInitialization——初始化剩余的单实例bean对象

AbstractApplicationContext.java

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    // 初始化用于类型转换的解析器
    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));
    }

    // Register a default embedded value resolver if no BeanFactoryPostProcessor
    // (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    // 初始化用于表达式解析的解析器
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    // 初始化所有非延迟加载的单实例bean对象
    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.
    beanFactory.freezeConfiguration();
    
    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons();
    }

这一步骤主要完成2件事情,并且该步骤执行完毕后,BeanFactory的初始化工作结束:

  • 初始化用于类型转换和表达式的解析器(ConversionService和EmbeddedValueResolver);
  • 初始化所有非延迟加载的单实例bean对象

12.finishRefresh——刷新后的动作

这一步骤执行了一些比较零散的动作,详见注释。

AbstractApplicationContext.java

protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    // 清理上下文级别的资源缓存(例如扫描中的ASM元数据)
    clearResourceCaches();
    
    // Initialize lifecycle processor for this context.
    // 初始化生命周期处理器
    initLifecycleProcessor();
    
    // Propagate refresh to lifecycle processor first.
    // 传播生命周期处理器,回调所有Lifecycle类型Bean的start方法
    getLifecycleProcessor().onRefresh();
    
    // Publish the final event.
    // 广播ContextRefreshedEvent事件
    publishEvent(new ContextRefreshedEvent(this));
    
    // Participate in LiveBeansView MBean, if active.
    // 激活状态下,参与LiveBeansView MBean
    LiveBeansView.registerApplicationContext(this);
}

13.resetCommonCaches——清除缓存

AbstractApplicationContext.java

protected void resetCommonCaches() {
    ReflectionUtils.clearCache();
    AnnotationUtils.clearCache();
    ResolvableType.clearCache();
    CachedIntrospectionResults.clearClassLoader(getClassLoader());
}

这一步骤清除一些无用的缓存,包括ReflectionUtils、AnnotationUtils、ResolvableType、CachedIntrospectionResults中的缓存。

总结:

纵观整个refresh方法,每个动作的职责都很清晰。在整个过程中,有对BeanFactory的处理,有对ApplicationContext的处理,有准备BeanPostProcessor的处理,有准备ApplicationListener的逻辑,最后初始化一些非延迟加载的单实例bean对象。refresh方法执行完毕后,也就宣告对ApplicationContext初始化完成。

3.8 小结

第3章到此就梳理完毕了,本章的主题是SpringBoot的IOC容器。回顾一下本章的梳理的内容:

(七)BeanFactory
(八)ApplicationContext
(九)SpringBoot对IOC容器的拓展
(十)Environment
(十一)BeanDefinition
(十二)后置处理器
(十三)IOC容器的启动流程

更多内容请查阅分类专栏:SpringBoot源码解读与原理分析

第4章主要梳理SpringBoot的核心引导:SpringApplication。主要内容包括:

  • SpringApplication的设计;
  • SpringApplication的启动阶段引导流程。

你可能感兴趣的:(spring,boot,java,spring,后端)