4-BeanFactory的增强:ApplicationCont

2020-02-25  本文已影响0人  鹏程1995

概要

过度

上面我们宏观介绍了refresh()的基本思路:

1.png

接下来我们按照框出来的四个部分依次介绍,本节介绍第一部分:启动前准备及验证。

内容简介

本文介绍ApplicationContext在调用刷新操作前的准备工作,主要涉及一些启动环境的校验、标记量的设置和准备工作。

所属环节

启动前准备及验证。

上下环节

上文: ApplicationContext已存在,调用refresh()重新载入;或者项目启动,加载配置文件后调用refresh()

下文: 开始进行刷新(先进行BeanFactory的相关设置)

源码解析

入口

public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    // 准备此 ApplicationContext
    prepareRefresh();

    // Tell the subclass to refresh the internal bean factory.
    // BeanFactory 的初始化及对应的 BD 的加载
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // Prepare the bean factory for use in this context.
    // 对 BeanFactory 中的一些和上下文相关的属性进行设置和同步。
    prepareBeanFactory(beanFactory);

    try {
      // Allows post-processing of the bean factory in context subclasses.
      // 定义了一个钩子,供子类实现
      postProcessBeanFactory(beanFactory);

      // Invoke factory processors registered as beans in the context.
      // 调用 BeanFactory 的后处理器对其进行处理
      invokeBeanFactoryPostProcessors(beanFactory);

      // Register bean processors that intercept bean creation.
      // 注册那些拦截 Bean 创建的后处理器
      // 注意,上面 invokeBeanFactoryPostProcessors() 各种实例化各种注册,操作的都是针对 factory 的后处理器。这里才是针对 bean
      // 的后处理器
      registerBeanPostProcessors(beanFactory);

      // Initialize message source for this context.
      // 初始化本 context 的 Message 源【国际化和本土化】【将对应的信息符号转化成对应的语言提示】
      // TODO 没啥需要,最后再看
      initMessageSource();

      // Initialize event multicaster for this context.
      // 初始化事件广播相关的东西
      initApplicationEventMulticaster();

      // Initialize other special beans in specific context subclasses.
      // 子实现类根据各自情况实现其他的特殊 Bean 的处理
      // 算是留下的一个钩子
      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();
    }
  }
}

还是之前的refresh()函数。我们主要介绍其中的prepareRefresh()方法。

刷新前的准备

/**
     * Prepare this context for refreshing, setting its startup date and
     * active flag as well as performing any initialization of property sources.
     */
// 准备此 ApplicationContext
// 设置启动时间和启动标志,初始化相应属性【什么事件、监听器之类的】
protected void prepareRefresh() {
  // Switch to active.
  this.startupDate = System.currentTimeMillis();
  this.closed.set(false);
  this.active.set(true);

  if (logger.isInfoEnabled()) {
    logger.info("Refreshing " + this);
  }

  // Initialize any placeholder property sources in the context environment.
  // 根据此 ApplicationContext 的上下文环境初始化对应的属性
  // 默认不干啥,留给子类覆盖
  // 可以和下一句呼应,也就是说根据环境设置必须设置的属性,如果没有,正好下一句直接检测报错
  initPropertySources();

  // Validate that all properties marked as required are resolvable:
  // see ConfigurablePropertyResolver#setRequiredProperties
  // 校验 ConfigurableEnvironment 中设置的必有属性是否有设置
  // 可以自己在前面的钩子中调用 getEnvironment().setRequiredProperties() 设置子项目要必须
  // 设置的属性
  getEnvironment().validateRequiredProperties();

  // Store pre-refresh ApplicationListeners...
  // ApplicationListeners 看样子只加不删,每次都会把旧的拷贝过去
  // TODO 这里的逻辑看看怎么回事,结合关闭操作代码吧。感觉要借助 earlyApplicationListeners 做个左手倒右手的事情
  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...
  // 将存储提前到来的事件的set准备好,初始化完成后会进行广播
  this.earlyApplicationEvents = new LinkedHashSet<>();
}

主要做了三件事:

  1. 设置启动标志量、记录启动时间点
  2. 进行环境必配置变量的验证
  3. 对监听器、事件存储进行刷新

其中我们主要介绍第二点。

环境验证

getEnvironment().validateRequiredProperties()是调用Environment的校验函数,如果有必设的值没有设置,会直接抛出异常结束。

我们一般会先设置哪些属性是必须设置的,然后再调用这个方法进行验证。如果要用的话,我们一般用前一句的钩子设置必须设的属性。

扩展

问题遗留

参考文献

上一篇下一篇

猜你喜欢

热点阅读