Spring应用上下文 ApplicationContext

Spring的ApplicationContext是更高级的IoC容器,提供事件机制、国际化和资源加载等功能。本文详细介绍了ApplicationContext的体系结构、刷新流程,包括BeanFactory创建、后置处理、事件监听器注册等关键步骤,以及refresh方法的详细过程。通过对AbstractApplicationContext的分析,揭示了Spring应用上下文的生命周期和核心功能。
摘要由CSDN通过智能技术生成

Spring 应用上下文 ApplicationContext

前面一系列文章都是围绕 BeanFactory 进行分析的,BeanFactory 是 Spring 底层 IoC 容器的实现,完成了 IoC 容器的基本功能。在实际的应用场景中,BeanFactory 容器有点简单,它并不适用于生产环境,我们通常会选择 ApplicationContext。ApplicationContext 就是大名鼎鼎的 Spring 应用上下文,它不仅继承了 BeanFactory 体系,还提供更加高级的功能,更加适用于我们的正式应用环境。如以下几个功能:

  • 继承 MessageSource,提供国际化的标准访问策略
  • 继承 ApplicationEventPublisher ,提供强大的事件机制
  • 扩展 ResourceLoader,可以用来加载多个 Resource,可以灵活访问不同的资源
  • 对 Web 应用的支持

ApplicationContext 体系结构

先来看看 ApplicationContext 接口的继承关系

可以看到 ApplicationContext 除了继承 BeanFactory 接口以外,还继承了 MessageSource、ApplicationEventPublisher、ResourceLoader 等接口

简单描述几个接口:

  • org.springframework.core.io.ResourceLoader,资源加载接口,用于访问不同的资源
  • org.springframework.context.ApplicationEventPublisher,事件发布器接口,支持发布事件
  • org.springframework.context.MessageSource,消息资源接口,提供国际化的标准访问策略
  • org.springframework.core.env.EnvironmentCapable,环境暴露接口,Spring 应用上下文支持多环境的配置
  • org.springframework.context.ApplicationContext,Spring 应用上下文,仅可读
  • org.springframework.context.ConfigurableApplicationContext,Spring 应用上下文,支持配置相关属性

接下来我们来看看它们的实现类的继承关系(部分)

简单描述上面几个关键的类:

  • org.springframework.context.support.AbstractApplicationContext,Spring 应用上下文的抽象类,实现了大部分功能,提供骨架方法交由子类去实现
  • org.springframework.web.context.ConfigurableWebApplicationContext,可配置的 Spring 应用上下文接口,支持 Web 应用
  • org.springframework.context.support.AbstractRefreshableConfigApplicationContext,支持设置 XML 文件
  • org.springframework.web.context.support.AbstractRefreshableWebApplicationContext,支持 Web 应用
  • org.springframework.web.context.support.AnnotationConfigWebApplicationContext,支持 Web 应用,可以设置 XML 文件,并可以扫描注解下面的 Bean
  • org.springframework.context.annotation.AnnotationConfigApplicationContext,支持扫描注解下面的 Bean
  • org.springframework.web.context.support.ClassPathXmlApplicationContext,支持设置 XML 文件,也可以从 classpath 下面扫描相关资源

ApplicationContext 的子类比较多,主要根据支持 Web、支持注解、支持 XML 文件三个功能进行区分,我们大致了解每个实现类的作用即可。其中基本的实现都是在 AbstractApplicationContext 这个抽象类中完成的,在它的 refresh() 方法体现了 Spring 应用上下文的生命周期。AbstractApplicationContext#refresh() 这个方法可以说是 Spring 应用上下文的准备阶段,在使用 Spring 时该方法会被调用,本文就围绕它进行展述。

可以先看到我的另一篇文章《精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化》,在 Spring MVC 启动过程中,创建 Spring 应用上下文后会调用其 refresh() 方法进行刷新,让 Spring 应用上下文准备就绪。

AbstractApplicationContext

org.springframework.context.support.AbstractApplicationContext,Spring 应用上下文的抽象类,实现了大部分功能,提供骨架方法交由子类去实现

先来看看它的相关属性

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
    
	public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";

	public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";

	public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

	static {
		// Eagerly load the ContextClosedEvent class to avoid weird classloader issues
		// on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
		ContextClosedEvent.class.getName();
	}

	/** Unique id for this context, if any. */
	private String id = ObjectUtils.identityToString(this);

	/** Display name. */
	private String displayName = ObjectUtils.identityToString(this);

	/** 父应用上下文 */
	@Nullable
	private ApplicationContext parent;

	/** 当前应用上下文的环境 */
	@Nullable
	private ConfigurableEnvironment environment;

	/** BeanFactory 的处理器 */
	private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

	/** 启动时间 */
	private long startupDate;

	/** 是否处于激活状态 */
	private final AtomicBoolean active = new AtomicBoolean();

	/** 是否处于关闭状态 */
	private final AtomicBoolean closed = new AtomicBoolean();

	/** 启动和销毁时的锁对象 */
	private final Object startupShutdownMonitor = new Object();

	/** 钩子函数,用于 JVM 关闭时的回调 */
	@Nullable
	private Thread shutdownHook;

	/** ResourcePatternResolver used by this context. */
	private ResourcePatternResolver resourcePatternResolver;

	/** LifecycleProcessor for managing the lifecycle of beans within this context. */
	@Nullable
	private LifecycleProcessor lifecycleProcessor;

	/** MessageSource we delegate our implementation of this interface to. */
	@Nullable
	private MessageSource messageSource;

	/** 事件广播器 */
	@Nullable
	private ApplicationEventMulticaster applicationEventMulticaster;

	/** 事件监听器 */
	private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

	/** 早期(Spring 应用上下文还未就绪)注册的时间监听器 */
	@Nullable
	private Set<ApplicationListener<?>> earlyApplicationListeners;

	/** 早期(Spring 应用上下文还未就绪)发布的事件 */
	@Nullable
	private Set<ApplicationEvent> earlyApplicationEvents;

	public AbstractApplicationContext() {
		this.resourcePatternResolver = getResourcePatternResolver();
	}

	public AbstractApplicationContext(@Nullable ApplicationContext parent) {
		this();
		setParent(parent);
	}
}

属性不多,上面都有注释

publishEvent 方法

publishEvent(ApplicationEvent event) 方法,发布事件,因为它继承了 ApplicationEventPublisher 事件发布器,如下:

@Override
public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
}

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");

    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        // 如果不是 ApplicationEvent 类型的事件,则封装成 PayloadApplicationEvent
        applicationEvent = new PayloadApplicationEvent<>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
        }
    }

    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        // 广播该事件
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // Publish event via parent context as well...
    // 父容器也要发布事件
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

过程如下:

  1. 如果不是 ApplicationEvent 类型的事件,则封装成 PayloadApplicationEvent
  2. 如果 earlyApplicationEvents 不为 null,则表示当前 Spring 应用上下文正在处于刷新阶段,还没有准备就绪,则先将这个早期事件添加至 earlyApplicationEvents;否则,Spring 应用上下文已经准备就绪了,此时就对该事件进行广播
  3. 如果存在父应用上下文,也需要进行广播

上面的第 2 步中的 earlyApplicationEvents 如果不为 null ,为什么 Spring 应用上下文还没有准备就绪呢?答案会在后面体现

addBeanFactoryPostProcessor 方法

addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) 方法,添加 BeanFactoryPostProcessor 处理器,如下:

@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
    Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
    this.beanFactoryPostProcessors.add(postProcessor);
}

直接往 beanFactoryPostProcessors 添加,BeanFactoryPostProcessor 处理器用于在 Spring 应用上下文刷新阶段对创建好的 BeanFactory 进行后缀处理

addApplicationListener 方法

addApplicationListener(ApplicationListener<?> listener) 方法,添加事件监听器,如下:

@Override
public void addApplicationListener(ApplicationListener<?> listener) {
    Assert.notNull(listener, "ApplicationListener must not be null");
    if (this.applicationEventMulticaster != null) {
        this.applicationEventMulticaster.addApplicationListener(listener);
    }
    this.applicationListeners.add(listener);
}

如果事件广播器不为空则将该监听器添加进去,然后再添加到本地的 applicationListeners 中

【核心】refresh 方法

refresh() 方法,Spring 应用上下文的刷新,让 Spring 应用上下文处于准备就绪状态,如下:

/**
 * 刷新上下文,在哪会被调用?
 * 在 **Spring MVC** 中,{@link org.springframework.web.context.ContextLoader#initWebApplicationContext} 方法初始化上下文时,会调用该方法
 */
@Override
public void refresh() throws BeansException, IllegalStateException {
    // <1> 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
    synchronized (this.startupShutdownMonitor) {

        // <2> 刷新上下文环境的准备工作,记录下容器的启动时间、标记'已启动'状态、对上下文环境属性进行校验
        prepareRefresh();

        // <3> 创建并初始化一个 BeanFactory 对象 `beanFactory`,会加载出对应的 BeanDefinition 元信息们
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // <4> 为 `beanFactory` 进行一些准备工作,例如添加几个 BeanPostProcessor,手动注册几个特殊的 Bean
        prepareBeanFactory(beanFactory);

        try {
            // <5> 对 `beanFactory` 在进行一些后期的加工,交由子类进行扩展
            postProcessBeanFactory(beanFactory);

            // <6> 执行 BeanFactoryPostProcessor 处理器,包含 BeanDefinitionRegistryPostProcessor 处理器
            invokeBeanFactoryPostProcessors(beanFactory);

            // <7> 对 BeanPostProcessor 处理器进行初始化,并添加至 BeanFactory 中
            registerBeanPostProcessors(beanFactory);

            // <8> 设置上下文的 MessageSource 对象
            initMessageSource();

            // <9> 设置上下文的 ApplicationEventMulticaster 对象,上下文事件广播器
            initApplicationEventMulticaster();

            // <10> 刷新上下文时再进行一些初始化工作,交由子类进行扩展
            onRefresh();

            // <11> 将所有 ApplicationListener 监听器添加至 `applicationEventMulticaster` 事件广播器,如果已有事件则进行广播
            registerListeners();

            // <12> 设置 ConversionService 类型转换器,**初始化**所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式)
            finishBeanFactoryInitialization(beanFactory);

            // <13> 刷新上下文的最后一步工作,会发布 ContextRefreshedEvent 上下文完成刷新事件
            finishRefresh();
        }
        // <14> 如果上面过程出现 BeansException 异常
        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }
            // <14.1> “销毁” 已注册的单例 Bean
            destroyBeans();

            // <14.2> 设置上下文的 `active` 状态为 `false`
            cancelRefresh(ex);

            // <14.3> 抛出异常
            throw ex;
        }
        // <15> `finally` 代码块
        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            // 清除相关缓存,例如通过反射机制缓存的 Method 和 Field 对象,缓存的注解元数据,缓存的泛型类型对象,缓存的类加载器
            resetCommonCaches();
        }
    }
}

整个过程比较长,每一个步骤都调用一个方法,过程如下:

  1. 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
  2. 应用上下文启动准备阶段,调用 prepareRefresh() 方法,说明:刷新上下文环境的准备工作,记录下容器的启动时间、标记'已启动'状态、对上下文环境属性进行校验
  3. BeanFactory 创建阶段,调用 obtainFreshBeanFactory() 方法,说明:创建并初始化一个 BeanFactory 对象 beanFactory,会加载出对应的 BeanDefinition 元信息们
  4. BeanFactory 准备阶段,调用 prepareBeanFactory() 方法,说明:为 beanFactory 进行一些准备工作,例如添加几个 BeanPostProcessor,手动注册几个特殊的 Bean
  5. BeanFactory 后置处理阶段,调用 postProcessBeanFactory(ConfigurableListableBeanFactory) 方法,说明:对 beanFactory 在进行一些后期的加工,交由子类进行扩展
  6. BeanFactory 后置处理阶段,调用 invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) 方法,说明:执行 BeanFactoryPostProcessor 处理器,包含 BeanDefinitionRegistryPostProcessor 处理器
  7. BeanFactory 注册 BeanPostProcessor 阶段,调用 registerBeanPostProcessors(ConfigurableListableBeanFactory) 方法,说明:对 BeanPostProcessor 处理器进行初始化,并添加至 BeanFactory 中
  8. 初始化内建 Bean:MessageSource,调用 initMessageSource() 方法,说明:设置上下文的 MessageSource 对象
  9. 初始化内建 Bean:Spring 事件广播器,调用 initApplicationEventMulticaster() 方
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值