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

4-BeanFactory的增强:ApplicationCont

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

    概要

    过度

    上面我们宏观介绍了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. 发送消息通知——启动完成

    扩展

    问题遗留

    参考文献

    相关文章

      网友评论

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

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