SpringFramework — IOC 生命周期概述

小龙 488 2022-06-01

ApplicationContext

ApplicationContext 的 refresh 方法时整个 IOC 容器初始化的核心,它一共分为 13 步:

ApplicationContext.refresh() 方法:

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. 初始化所有剩下的单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 12. 完成容器的创建工作
            finishRefresh();
        } // catch ......

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            // 13. 清除缓存
            resetCommonCaches();
        }
    }
}

下面来研究一下,这里面的每一步都做了那些事

prepareRefresh - 初始化前的处理

protected void prepareRefresh() {
    // 此处会记录启动时间,切换IOC容器的状态
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    // logger ......

    // 初始化属性配置
    initPropertySources();

    // 属性校验
    getEnvironment().validateRequiredProperties();

    // 省略源码 - 初始化早期事件
}

这一步中,大多数动作都是前置性的准备,而且这些动作几乎都用不到

obtainFreshBeanFactory - 初始化 BeanFactory

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

这个方法在基于 xml 配置文件的 ApplicationContext 中,该步会解析 xml 配置文件,封装 BeanDefinition 。但是基于注解配置类的 ApplicationContext 就不会在这一步进行。

GenericApplicationContexrefreshBeanFactory 方法中,有一个 CAS 判断动作,他控制着 GenericApplicationContext 不断反复刷新。所以从这里可以知道基于 xml 配置文件的 ApplicationContext 可以反复刷新,基于注解配置类的 ApplicationContext 只能刷新一次

prepareBeanFactory - BeanFactory的预处理动作

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 给BeanFactory中设置类加载器、表达式解析器
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 1.3.1 编码注册ApplicationContextAwareProcessor
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // 1.3.2 以下几个Aware接口的回调注入不由BeanFactory负责
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 1.3.3 以下几个类型的自动注入会直接绑定
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 又编码注册监听器钩子
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // 又是Load Time Weaver相关的部分,AOP再解释
    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()));
    }

    // 注册默认的运行时环境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());
    }
}

这个方法中的信息量有点多,分开解析

编码注册 ApplicationContextAwareProcessor

在 Aware 接口注入的后置处理器中,其核心作用的 ApplicationContextAwareProcessor 就是在此处注册的。而且它负责 6 个 Aware 接口的注入。这一点在源码中证实了,说明 ApplicationContextAwareProcessor 接管 BeanFactory 自动注入这一设计。

如何理解这一设计:BeanFactory 来自 spring-beans 包,而 ApplicationContext 来自 spring-context 包。由于 context 依赖 beans ,而 beans 本身可以单独存在。在没有 context 包的环境下,BeanFactory 本身也可以作为一个普通的 IOC 容器来处理依赖查找和自动类型注入,而引入 context 包后,出现了更多的内部组件,注入的要求也就更复杂。本着单一职责与职责分离的原则,BeanFactory 还是干原来的事情,扩展的 Aware 回调注入则交给 context 包中的 ApplicationContextAwareProcessor 搞定。

ignoreDependencyInterface 的设计

既然有 6 个 Aware 回调接口的工作被 ApplicationContextAwareProcessor 接管了,那 BeanFactory 本身就不再需要考虑这 6 个接口的注入了。这 6 个接口最终会存储到 AbstractAutowireCapableBeanFactoryignoredDependencyInterfaces 变量中:

private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();

这些被存起来的 Aware 接口使用的时机,是在 bean 生命周期中的属性赋值 populateBean 阶段:

 // ......
    if (needsDepCheck) {
        if (filteredPds == null) {
            // 此处ignoreDependencyInterface会被利用
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    if (pvs != null) {
        // 将PropertyValues应用给bean
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

上面的 filterPropertyDescriptorsForDependencyCheck 方法,内部就使用了 ignoredDependencyInterfaces 这个集合检查那些依赖的 Aware 接口。

Aware 接口都会定义一个 setXXX 的方法(如 BeanFactoryAware 接口的 setBeanFactory 方法),同时实现了 Aware 接口的方法通常都会在成员属性中定义一个与回调注入类型相同的属性变量(如实现了 BeanFactoryAware 接口的类,通常都会定义一个 private BeanFactory beanFactory; )。如果是按照这种设计编写的代码,BeanFactory 会认定这个属性可以受自动注入的支持( autowire-mode ),并对这个属性进行依赖注入。简单的讲,BeanFactory 可以支持的自动注入的属性必须带有 setter 方法,而 Aware 接口的方法定义风格刚好是 setter 的风格,所以只需要求实现了 Aware 接口的类,定义属性时,属性名与 setter 方法对应的名称一致即可( setPerson → person )。

registerResolvableDependency的设计

// Map from dependency type to corresponding autowired value.
// 从依赖属性的类型映射到相应的自动装配值
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {
    Assert.notNull(dependencyType, "Dependency type must not be null");
    if (autowiredValue != null) {
        // check throw ex ......
        this.resolvableDependencies.put(dependencyType, autowiredValue);
    }
}

BeanFactory 在遇到特定类型的属性注入时,会直接从这个 resolvableDependencies 的 Map 中找出对应的值,直接注入进去(相当于预先指定好了哪个类型注入哪个值,不需要额外考虑)。

postProcessBeanFactory - BeanFactory的后置处理

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

这个方法在 AbstractApplicationContext 中是一个模板方法,它的重写在基于 web 环境的 ApplicationContext 子类中有实现

invokeBeanFactoryPostProcessors - 执行BeanFactoryPostProcessor

它会执行所有的 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor ,主要工作是包扫描、解析配置类等

registerBeanPostProcessors - 初始化BeanPostProcessor

它会把所有的 BeanPostProcessor 都注册到位

initMessageSource - 初始化国际化组件

它涉及到国际化的知识

initApplicationEventMulticaster - 初始化事件广播器

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        // logger ......
    }
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        // logger ......
    }
}

这部分的内容非常简单了,它会构造一个 SimpleApplicationEventMulticaster ,并注册进 BeanFactory 中,仅此而已。

onRefresh - 子类扩展的刷新动作

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

是一个模板方法,而它的扩展在纯 Spring 环境下是找不到的,不过在 SpringBoot 中,有子类对这个方法的重写

registerListeners - 注册监听器

protected void registerListeners() {
    // 注册所有已经被创建出来的ApplicationListener,绑定到ApplicationEventMulticaster中
    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!
    // 此处不会实例化ApplicationListener,而是只绑定name
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 广播早期事件(后续再解释)
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

这个方法共分为三个小段,条理也非常清晰。不过要注意一点,此处那些没有初始化的 ApplicationListener 并没有被实例化,而是会等到下一步 finishBeanFactoryInitialization 方法中才会被创建出来

finishBeanFactoryInitialization - 初始化剩余的单实例bean

这个方法就是一个一个的循环初始化那些非延迟加载的单实例 bean

finishRefresh - 刷新后的动作

protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    // 清除上下文级别的资源缓存
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    // 为当前ApplicationContext初始化一个生命周期处理器
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    // 将refresh的动作传播到生命周期处理器
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    // 广播事件
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

它主要是初始化 LifecycleProcessor 、广播刷新完成的事件

resetCommonCaches - 清除缓存

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

这一步就是删除在初始化过程中保存的各种各样的缓存

小结

在整个 refresh 方法中,每个动作的职责都很清晰,而且非常的有条理性。这个过程中,有对 BeanFactory 的处理,有对 ApplicationContext 的处理,有处理 BeanPostProcess 的逻辑,有准备 ApplicationListener 的逻辑,最后它会初始化那些非延迟加载的单例 bean。整个 refresh 方法走下来,ApplicationContext 也就被初始化完毕了。

2 ApplicationContext初始化中的扩展点

梳理一下,整个 ApplicationContext 的初始化逻辑中,都有哪些扩展点可供我们切入利用。清楚地理解这些扩展点,可以让我们在后续扩展 Spring 时更加容易和游刃有余。

一般情况下,我们不会在 ApplicationContext 的初始化和 refresh 动作之间作太多的处理,主要还是从 refresh 方法本身出发考虑,故以下梳理的扩展点都来自于 refresh 方法开始触发时。

2.1 invokeBeanFactoryPostProcessors

前四个方法中,在普通的 ApplicationContext 下都无法切入,所以只能在第 5 步 invokeBeanFactoryPostProcessors 方法中切入了。而这个方法中可供切入的点实在是太多了

2.1.1 ImportSelector&ImportBeanDefinitionRegistrar

第一个竟然不是 BeanFactoryPostProcessor 或者 BeanDefinitionRegistryPostProcessor ,原因是它们的执行时机通常都在 ConfigurationClassPostProcessor 之后,而 ConfigurationClassPostProcessor 的执行过程中,会解析 @Import 注解,取出里面的 ImportBeanDefinitionRegistrar 并执行,所以第一个扩展点是 ImportSelectorImportBeanDefinitionRegistrar 了。

ImportSelector 在该阶段只能拿到当前 @Import 标注的注解配置类的信息(如下面代码中 BarImportSelector 只能拿到 BarConfiguration 的信息)

@Import(BarImportSelector.class)
@Configuration
public class BarConfiguration { ... }

ImportBeanDefinitionRegistrar 在该阶段除了可以获取到当前 @Import 标注的注解配置类的信息之外,更重要的是能拿到 BeanDefinitionRegistry ,由此可供扩展的动作主要是给 BeanDefinitionRegistry 中注册新的 BeanDefinition

2.1.2 BeanDefinitionRegistryPostProcessor

使用 BeanDefinitionRegistryPostProcessor 可以拿到 BeanDefinitionRegistry 的 API,直接向 IOC 容器中注册新的 BeanDefinition

自定义的 BeanDefinitionRegistryPostProcessor 执行时机比内置的 ConfigurationClassPostProcessor 要晚,这也是 SpringFramework 最开始的设计( ConfigurationClassPostProcessor 实现了 PriorityOrdered 接口,这个接口的优先级最高)。

2.1.3 BeanFactoryPostProcessor

BeanFactoryPostProcessor 的切入时机紧随 BeanDefinitionRegistryPostProcessor 之后,需要注意一下,在 BeanFactoryPostProcessor 的切入回调中,可以拿到的参数是 ConfigurableListableBeanFactory ,拿到它就意味着,我们在这个阶段按理来讲不应该再向 BeanFactory 中注册新的 BeanDefinition 了,只能获取和修改现有的 BeanDefinition 。

BeanFactoryPostProcessor 的处理阶段是可以提早初始化 bean 对象的,因为这个阶段下只有 ApplicationContextAwareProcessor 注册到了 BeanFactory 中,没有其余关键的 BeanPostProcessor ,所以这个阶段初始化的 bean 有一个共同的特点:能使用 Aware 回调注入,但无法使用 @Autowired 等自动注入的注解进行依赖注入,且不会产生任何代理对象。

2.2 registerBeanPostProcessors

所有 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 都处理完之后,下一步是初始化 BeanPostProcessor 。这个逻辑我们之前也都看过了,但这个阶段没有可以切入影响该阶段的时机

2.3 finishBeanFactoryInitialization

来到最复杂的初始化 bean 的这一步了。这里面的切入时机才多呢,前面看 bean 的实例化和初始化过程中,有非常多可供切入的时机

2.3.1 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

从 bean 的创建阶段之前,就有 InstantiationAwareBeanPostProcessor 来拦截创建了,每个 bean 在创建之前都会尝试着使用 InstantiationAwareBeanPostProcessor 来代替创建,如果没有任何 InstantiationAwareBeanPostProcessor 可以拦截创建,则会走真正的 bean 对象实例化流程。

在 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法中,只能拿到 bean 对应的 Class 类型,以及 bean 的名称(当然啦,本来就是凭空造,有 Class 类型就够了),如果方法没有返回值,则代表 InstantiationAwareBeanPostProcessor 不参与拦截 bean 创建的动作。

2.3.2 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors

如果在实例化 bean 之前,InstantiationAwareBeanPostProcessor 没有起到作用,就会通过构造器创建对象。如果一个 bean 有多个构造器,如何选择合适的构造器去创建对象就是很重要的一步。筛选构造器的核心方法是 determineConstructorsFromBeanPostProcessors ,它会在底层寻找所有 SmartInstantiationAwareBeanPostProcessor ,回调 determineCandidateConstructors 方法获取可选择的构造器:

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
        throws BeansException {
    if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
                if (ctors != null) {
                    return ctors;
                }
            }
        }
    }
    return null;
}

这个 SmartInstantiationAwareBeanPostProcessor 的使用了,如果在这里打入 Debug 断点时,程序代码运行时可以停在断点,但不会有任何返回,这个现象的产因是:默认情况下 ConfigurationClassPostProcessor 会向 IOC 容器注册一个 ImportAwareBeanPostProcessor ,但它又没有重写 determineCandidateConstructors 方法,就造成了这个现象。

所以一般情况下,SmartInstantiationAwareBeanPostProcessor 在 SpringFramework 内部是用不到的,我们平时开发不是特殊场景也用不上,这个小伙伴们知道一下就可以了。

2.3.3 MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition

在 createBeanInstance 方法执行完毕之后,此时 bean 对象已经创建出来了,只是没有任何属性值的注入而已。此时 doCreateBean 方法会走到 applyMergedBeanDefinitionPostProcessors 方法,让这些 MergedBeanDefinitionPostProcessor 去收集 bean 所属的 Class 中的注解信息。

有三个关键的 MergedBeanDefinitionPostProcessor ,它们分别是 InitDestroyAnnotationBeanPostProcessor (收集 @PostConstruct 与 @PreDestroy 注解)、CommonAnnotationBeanPostProcessor (收集 JSR 250 的其它注解)、AutowiredAnnotationBeanPostProcessor (收集自动注入相关的注解)。

在此处切入扩展,意味着可以对 bean 对象所属的 Class 作一些处理或者收集的动作(当然也可以进行属性赋值等动作,但考虑到职责分离,该步骤还是不要瞎搞为好 ~ ~)。

2.3.4 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

等这些 MergedBeanDefinitionPostProcessor 都工作完毕后,此时 bean 对象所属的 Class 中的信息都收集完毕了,接下来还得让 InstantiationAwareBeanPostProcessor 出场,它要负责控制是否继续走接下来的 populateBean 和 initializeBean 方法初始化 bean 。

所以如果在这里切入扩展的话,只能做到流程控制的作用。

2.3.5 InstantiationAwareBeanPostProcessor#postProcessProperties

它调用的是 postProcessProperties 方法,这个步骤会将 bean 对象对应的 PropertyValues 中封装赋值和注入的数据应用给 bean 实例。通常情况下,在该阶段 SpringFramework 内部起作用的后置处理器是 AutowiredAnnotationBeanPostProcessor ,它会搜集 bean 所属的 Class 中标注了 @Autowired 、@Value 、@Resource 等注解的属性和方法,并反射赋值 / 调用。

在此处扩展逻辑的话,相当于扩展了后置处理器的属性赋值 + 依赖注入的自定义逻辑。当这个动作执行完毕之后,就不会再有属性赋值和组件注入的回调了。

2.3.6 BeanPostProcessor

接下来的两个动作就发生在 initializeBean 方法中了,它就是 BeanPostProcessor 的前后两个执行动作 postProcessBeforeInitialization 和 postProcessAfterInitialization 。进入到 initializeBean 方法后,bean 的生命周期已经到了初始化逻辑回调的阶段,此时 bean 中应该注入的属性均已完备,BeanPostProcessor 的切入也只是给 bean 添加一些额外的属性的赋值、回调等等,以及生成代理对象。

所以,在此处切入扩展逻辑,相当于针对一个接近完善的 bean 去扩展 / 包装。当后置处理器执行完 postProcessAfterInitialization 方法后,基本上就代表 bean 的初始化结束了。

2.3.7 SmartInitializingSingleton

它来自 SpringFramework 4.1 ,它是在所有非延迟加载的单实例 bean 全部初始化完成后才回调的。这个阶段底层会取出所有实现了 SmartInitializingSingleton 接口的 bean ,去回调 afterSingletonsInstantiated 方法。
这个设计只是为了让 BeanFactory 也能插一脚初始化的后处理,仅此而已。

这个扩展是针对单个 bean 的, 不是切入所有 bean 的,所以严格意义上讲它属于 bean 初始化的扩展点。不过话又说回来,它是在 BeanFactory 把单实例 bean 都初始化完成后统一回调的,又属于一个整体动作,所以小册也就把它拿出来了。


# IOC