美文网首页
4-BeanFactory的增强:ApplicationCont

4-BeanFactory的增强:ApplicationCont

作者: 鹏程1995 | 来源:发表于2020-02-25 16:03 被阅读0次

    概要

    过度

    上面我们宏观介绍了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的校验函数,如果有必设的值没有设置,会直接抛出异常结束。

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

    扩展

    问题遗留

    参考文献

    相关文章

      网友评论

          本文标题:4-BeanFactory的增强:ApplicationCont

          本文链接:https://www.haomeiwen.com/subject/ftgtchtx.html