源码学习 Spring 容器初始化流程


共计 15146 个字符,预计需要花费 38 分钟才能阅读完成。

0. 简介

本文以 ClassPathXmlApplicationContext 源码学习 Spring 初始化流程,那么首先要了解它实现了哪些接口,可以直观地了解到它具备了哪些能力。

源码学习 Spring 容器初始化流程

/>

最重要的一点是它实现了 BeanFactory 接口,BeanFactory 其实就是常说的 ioc 容器,因为它实现了该接口,所以 ClassPathXmlApplicationContext 也是 ioc 容器。重点来了ClassPathXmlApplicationContext 虽然实现了接口,但是它重写 BeanFactory 的方法都是委托给了成员变量 beanFactory 去实现。下面的代码都是其基类实现的。

// AbstractApplicationContext 实现
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
    assertBeanFactoryActive();
    return getBeanFactory().getBean(requiredType);
}

// AbstractRefreshableApplicationContext 实现
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
    DefaultListableBeanFactory beanFactory = this.beanFactory;
    if (beanFactory == null) {
        throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                "call 'refresh' before accessing beans via the ApplicationContext");
    }
    return beanFactory;
}

ClassPathXmlApplicationContext 不但实现了 BeanFactory 接口,并且实现了其他的接口为容器扩展了功能如:消息国际化资源解析器事件发布获取环境变量等功能。

构造函数时创建 ioc 容器的入口,代码如下:

public ClassPathXmlApplicationContext(
        String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
        throws BeansException {

    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}

执行构造方法,每个 ApplicationContext 都有自己的实现,但是都会初始化容器状态标识 activeclosed

ClassPathXmlApplicationContext 在执行构造方法时,并不会初始化 beanFactory。而 AnnotationConfigApplicationContext 在初始化时并创建好 beanFactory,并将 internalConfigurationAnnotationProcessorinternalAutowiredAnnotationProcessor 等几个后 bean 后处理器注入,用于解析 @Configuration@Autowired等注解。如果全部以 xml 的形式给容器注入 bean,那么是不需要这几个后处理器的,但是如果需要配置文件的方式也能使用注解,就需要配置 <context:annotation-config/>

不管怎么说,都会执行 refresh() 方法用于刷新容器。其中 AbstractApplicationContextrefresh() 方法,代码如下:

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 执行刷新容器前的一些必要方法
        prepareRefresh();

        // 调用子类获取到 bean 工厂
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 配置 bean 工厂,以增强功能
        prepareBeanFactory(beanFactory);

        try {
            // 修改和调整 Bean 的定义(默认没有实现)
            postProcessBeanFactory(beanFactory);

            // 调用后置处理器
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册 BeanPostProcessor,用于修改和增强 bean 的功能
            registerBeanPostProcessors(beanFactory);

            // 为上下文初始化 Message 源,即对不同语言的消息体进行国际化处理
            initMessageSource();

            // 初始化容器事件传播器
            initApplicationEventMulticaster();

            // 调用子类的某些特殊 Bean 初始化方法
            onRefresh();

            // 为事件传播器注册事件监听器(这里用到了观察者模式)
            registerListeners();

            // 初始化 Bean,并对 lazy-init 属性进行处理
            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);
            }

            // 销毁创建的单态 Bean
            destroyBeans();

            // 取消 refresh 操作,重置容器的同步标识.
            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. prepareRefresh

protected void prepareRefresh() {

    // 设置容器的启动时间,以便在刷新容器时进行时间跟踪
    this.startupDate = System.currentTimeMillis();
    // 容器在关闭时会设置该值为true,此时容器不能再进行一些初始化操作。
    this.closed.set(false);
    // 将容器的活动状态设置为true,表示容器当前处于活动状态。
    this.active.set(true);

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

    // 初始化容器中可能使用的占位符属性源,例如 ${some.property},确保这些占位符被正确解析和设置。(这里的属性包含 JVM 属性 systemProperties,和操作系统的环境变量 systemEnvironment)
    // 这是个空方法,是留给子类实现的。
    initPropertySources();

    // 验证所需要的属性都存在,否则抛出异常
    getEnvironment().validateRequiredProperties();

    // 设置监听器
    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);
    }

    this.earlyApplicationEvents = new LinkedHashSet<>();
}

通过继承 ClassPathXmlApplicationContext 可以重写 initPropertySources() 方法,启动时校验必要参数。

public class MyInitApplicationContext extends ClassPathXmlApplicationContext {

    public MyInitApplicationContext(String configLocation) throws BeansException {
        super(configLocation);
    }

    @Override
    protected void initPropertySources() {
        super.initPropertySources();
        System.out.println("test");
        getEnvironment().setRequiredProperties("aaa");
    }
}

2. obtainFreshBeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

    // 自己定义了抽象的 refreshBeanFactory() 方法,具体实现交给了自己的子类
    refreshBeanFactory();
    return getBeanFactory();
}

protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

obtainFreshBeanFactory 方法用于创建 bean 工厂,调用 refreshBeanFactory 方法为一个抽象方法,需要子类自行实现。这里有一个好处,就是比如使用 xml 文件和注解方式,因为他们获取 bean 信息方式不同,可以通过自己重写该方法创建工厂。

refreshBeanFactory() 方法交由子类 AbstractRefreshableApplicationContext 实现:

@Override
protected final void refreshBeanFactory() throws BeansException {
    // 如果已经建立了 IoC 容器,则销毁并关闭容器
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 创建 beanFactory 容器,DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        // 添加一些自定义操作
        customizeBeanFactory(beanFactory);
        // 载入 BeanDefinition,在当前类中只定义了抽象的 loadBeanDefinitions() 方法,具体实现 调用子类容器
        loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

loadBeanDefinitions() 方法交由子类 AbstractXmlApplicationContext 实现:

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // 创建用于从 Xml 中读取 BeanDefinition 的读取器
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // 配置 BeanDefinition 的读取器
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    // 为 beanDefinition 读取器设置 资源加载器,由于本类的基类 AbstractApplicationContext
    // 继承了 DefaultResourceLoader,因此,本容器自身也是一个资源加载器
    beanDefinitionReader.setResourceLoader(this);
    // 设置 SAX 解析器,SAX(simple API for XML)是另一种 XML 解析方法。相比于 DOM,SAX 速度更快,占用内存更小。
    // 它逐行扫描文档,一边扫描一边解析。相比于先将整个 XML 文件扫描进内存,再进行解析的 DOM,SAX 可以在解析文档的
    // 任意时刻停止解析,但操作也比 DOM 复杂。
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // 初始化
    initBeanDefinitionReader(beanDefinitionReader);
    // Bean 读取器真正实现加载的方法
    loadBeanDefinitions(beanDefinitionReader);
}

读取 BeanDefinition 的真正方法:

/**
 * ClassPathXmlApplicationContext 与 FileSystemXmlApplicationContext 在这里的调用出现分歧,
 * 各自按不同的方式加载解析 Resource 资源,最后在具体的解析和 BeanDefinition 定位上又会殊途同归。
 */
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

3. prepareBeanFactory

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 设置类加载器和属性、资源解析器
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 注册 AwareProcessor,用来给实现了 xxxAware 接口的类扩展功能
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

    // 是忽略指定接口类型的属性的自动注入,而通过其他方式实现注入(通过上面的 ApplicationContextAwareProcessor 进行属性注入)
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 用于动态注册某些类型的依赖,使其可以被 Spring 容器自动注入
    // 第一个参数为:希望注入的类型,第二个参数为当遇到这种希望注入的类型时,时间注入该对象
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 注册检测和解析实现 ApplicationListener 接口的后处理器
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // 检测是否包含特定 bean,有则加入对应的后处理器
    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()));
    }

    // 注册默认环境bean。environment、systemProperties、systemEnvironment
    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());
    }
}

对 BeanFactory 进行各种功能填充。其实如果自己直接 new 一个 BeanFactory,再添加上某些组件,也能够实现一个简单的容器。

这里主要是设置了一些类加载器和属性、资源解析器,还注册了一些后处理器用户处理实现特定接口的类,还注册了几个环境单例 bean。

4. postProcessBeanFactory

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

postProcessBeanFactory 方法主要用于在 Spring 容器实例化 bean 之前,修改和调整 bean 的定义。默认没有实现,子类可以重写。(ClassPathXmlApplicationContext 的基类 AbstractApplicationContext 对该方法并没有实现)

该方法与下面的 invokeBeanFactoryPostProcessors 方法效果一样,都是可以直接操作 beanFactory,可以新增、修改 bean 的定义。

5. invokeBeanFactoryPostProcessors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

调用各种 BeanFactoryPostProcessor,以实现对 bean 定义的新增和修改等,包括 spring 本身的和自己实现的 BeanFactoryPostProcessor 接口的类,通过委托 PostProcessorRegistrationDelegate 实现。

6. registerBeanPostProcessors

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

注册 BeanPostProcessor,同样通过委托 PostProcessorRegistrationDelegate 实现。(注意这里是注册,而不是执行)

特性 BeanFactoryPostProcessor BeanPostProcessor
执行时机 在 Bean 定义加载后、Bean 实例化之前。 在 Bean 实例化后、初始化方法之前或之后。
作用范围 主要用来修改或定制 Bean 定义(如修改属性、构造函数参数等)。 主要用来修改或增强 Bean 实例的行为。
执行对象 操作的是 BeanFactoryBeanDefinition,改变 Bean 的元数据。 操作的是已经实例化的 Bean 对象。
修改内容 可以修改 Bean 的定义,如属性、依赖等。 可以修改实例化后的 Bean,增加自定义逻辑或增强功能。
常见用途 修改 Bean 配置、条件注册 Bean、动态改变 Bean 定义。 增强 Bean 功能、AOP、日志记录、延迟初始化等。

7. initMessageSource

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 (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
            HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
            if (hms.getParentMessageSource() == null) {
                // Only set parent context as parent MessageSource if no parent MessageSource
                // registered already.
                hms.setParentMessageSource(getInternalParentMessageSource());
            }
        }
        if (logger.isTraceEnabled()) {
            logger.trace("Using MessageSource [" + this.messageSource + "]");
        }
    }
    else {
        // Use empty MessageSource to be able to accept getMessage calls.
        DelegatingMessageSource dms = new DelegatingMessageSource();
        dms.setParentMessageSource(getInternalParentMessageSource());
        this.messageSource = dms;
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
        }
    }
}

8. 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);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        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,并根据容器中是否已经存在相应的 bean 来进行初始化。

9. onRefresh

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

空方法,用于留给子类进行扩展。

10. registerListeners

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!
    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);
        }
    }
}

所有注册的 bean 中查找监听器,注册到应用事件广播器中。

11. finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 如果有的话,初始化默认转换服务。
    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));
    }

    // 注册嵌入式值解析器,以支持占位符(placeholders)解析的功能。例如:${property.name}
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // 初始化 LoadTimeWeaverAware 实例
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // 停止使用临时类加载器,并将其清除。
    beanFactory.setTempClassLoader(null);

    // 锁定 beanFactory 配置。一旦进入这个阶段,Spring 假设所有的 Bean 定义已经准备就绪,锁定配置,以提升性能。
    // 1. 不再允许新增或修改 Bean 定义 2. 可以更高效地缓存元数据,例如 Bean 的依赖关系或类型信息。
    beanFactory.freezeConfiguration();

    // 实例化所有非延迟加载的 bean
    beanFactory.preInstantiateSingletons();
}

初始化剩下的非懒加载实例,程序员自己编写的大部分 bean 都是在这里进行初始化的。在这里调用了 getBean 方法,创建了非惰性的 bean 实例。getBean 方法其中会调用 createBean 方法,毕竟 getBean 所需要获取的 bean

这里具体就涉及到了 bean 的生命周期,比较复杂,可以当作另外一个探究的点。

12. finishRefresh

protected void finishRefresh() {
    // 清楚资源缓存
    clearResourceCaches();

    // 初始化生命周期处理器
    initLifecycleProcessor();

    // 触发生命周期处理器的刷新事件
    getLifecycleProcessor().onRefresh();

    // 发布上下文刷新事件
    publishEvent(new ContextRefreshedEvent(this));

    // 注册到 LiveBeansView
    // LiveBeansView 是 Spring 提供的工具类,用于调试和监控应用中定义的 bean。
    LiveBeansView.registerApplicationContext(this);
}

Tips:清朝云网络工作室

阅读剩余
THE END