4-BeanFactory的增强:ApplicationCont

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

概要

过度

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

1.png

接下来我们按照框出来的四个部分依次介绍,本节介绍的是错误验证及启动事件的广播。

内容简介

通过上面的几步,我们基本把能配置的都配置完了。但是还有一个问题,很多时候我们注册的BD配置是有问题的,比如:

在工作中经常遇到的是JSF服务不存在,也就是找不到分布式服务的服务提供者。

所以,我们直接把所有的非懒加载的单例都进行实例化,这样如果有什么低级错误,在启动时就报错了,不会等到上线一天之后突然报警。

我们本节介绍的还有一个内容是相关事件的广播,也可以看作是上面各种context配置的一次使用。

所属环节

错误验证及启动事件的广播。

上下环节

上文: BeanFactoryApplicationContext 的配置

下文:启动结束,可以开始服务

源码解析

入口

还是把refresh()贴出来:

// TODO 模版方法
@Override
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();
    }
  }
}

��我们关注的是finishBeanFactoryInitialization()finishRefresh()两行代码干的事。

初始化所有单例

/**
     * Finish the initialization of this context's bean factory,
     * initializing all remaining singleton beans.
     */
// 完成 BeanFactory 的初始化
// 完成剩余的非懒加载单例 Bean 的实例化
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
  // Initialize conversion service for this context.
  // 从配置的 value 反序列化:
  // 1. 使用我们上面的 PropertyEditorRegistrar 之类的来做
  // 2. 使用 converter
  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));
  }

  // Register a default embedded value resolver if no bean post-processor
  // (such as a PropertyPlaceholderConfigurer bean) registered any before:
  // at this point, primarily for resolution in annotation attribute values.
  // TODO 这个是做什么的?? 在什么时候从 BeanFactory 中拉出来并发挥作用的???
  if (!beanFactory.hasEmbeddedValueResolver()) {
    beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
  }

  // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
  // 一个 aware ,用来获得项目启动时间的,在项目启动时对其进行初始化
  String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
  for (String weaverAwareName : weaverAwareNames) {
    getBean(weaverAwareName);
  }

  // Stop using the temporary ClassLoader for type matching.
  beanFactory.setTempClassLoader(null);

  // Allow for caching all bean definition metadata, not expecting further changes.
  // 不再允许 BD 的修改
  // 【可以继续注册新的BD】
  // 【不许修改注册的 bd ,但是你自己拉出来的 mbd 还是可以继续用后处理器修改的,改完还能自己缓存】
  beanFactory.freezeConfiguration();

  // 至此,完成对 BeanFactory 的所有初始化操作


  // Instantiate all remaining (non-lazy-init) singletons.
  // 将 "完成剩余的非懒加载单例 Bean 的实例化" 工作委托给 BeanFactory
  beanFactory.preInstantiateSingletons();
}

我感觉这个函数做的东西有点杂乱:

实例化和注册 ConversionService.class

ConversionService.class类型的进行了实例化和注册。它的职能是将指定的配置入参String序列化成对应的类型。和prepareBeanFactory()中的beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));类似,不过那里只是硬编码添加了对资源加载的解析。

当然,这里是context增加了对ConversionService的支持。我们该从哪入手去定制第二种情况的配置呢?通过CustomEditorConfigurer,这是个BeanFactoryPostProcessor。言尽于此。

LoadTimeWeaverAware对提前实例化

卧槽,这里看不懂,ApplicationContext虽然增加了对LoadTimeWeaverAware的支持,但是它已经通过后处理器提供了支持,这里为啥要提前手动加载一次?

初始化非懒加载的单例

委托给了beanFactory.preInstantiateSingletons()。这里不再细说。

散发初始化完成的事件

这里对应的是refresh()finishRefresh();一句:

protected void finishRefresh() {
  // Clear context-level resource caches (such as ASM metadata from scanning).
  clearResourceCaches();

  // TODO 这个生命周期控制,还不清楚
  // Initialize lifecycle processor for this context.
  // LifecycleProcessor ,实现此接口,Spring 框架会在启动时调用它的 start ,结束时调用 stop
  // 后台进程的优先选择。。。。。
  initLifecycleProcessor();

  // Propagate refresh to lifecycle processor first.
  getLifecycleProcessor().onRefresh();

  // 发布事件
  // Publish the final event.
  publishEvent(new ContextRefreshedEvent(this));

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

做了两件事:

  1. 增加对生命周期的支持,调用了生命周期的钩子【个人感觉这里有点多余,用事件通知完全能替代这部分功能
  2. 发送消息通知——启动完成

扩展

问题遗留

参考文献

上一篇 下一篇

猜你喜欢

热点阅读