Code source Spring5 11 - méthode d'actualisation de l'actualisation du conteneur (version annotée)

Bienvenue à tous de prêter attention à  github.com/hsfxuebao  , j'espère que cela vous sera utile. Si vous pensez que c'est possible, veuillez cliquer sur Star.

Tout d'abord, il doit être clair que la méthode refresh() appelée ici est le AnnotationConfigApplicationContextcontexte et obtainFreshBeanFactory()que le type beanFactoryréel est DefaultListableBeanFactory.

Tout d'abord, regardons le code global. La méthode refresh() est très claire, car elle encapsule toutes les fonctions dans différentes méthodes. Nous présenterons ces méthodes une par une plus tard.

// 容器刷新的十二大步骤
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 容器启动的状态
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

      // Prepare this context for refreshing.
      // 1.准备上下文环境,作用就是初始化一些状态和属性,为后面的工作做准备。
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      /** 2. 工厂创建:BeanFactory 第一次开始创建的时候,有xml解析逻辑
       *      2.1、创建BeanFactory对象
       *     2.2、xml解析
       *           传统标签解析:bean、import等
       *           自定义标签解析 如:<context:component-scan base-package="org.example"/>
       *           自定义标签解析流程:
       *              a、根据当前解析标签的头信息找到对应的namespaceUri
       *              b、加载spring所以jar中的spring.handlers文件。并建立映射关系
       *              c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
       *              d、调用类的init方法,init方法是注册了各种自定义标签的解析类
       *              e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
       *        2.3、把解析出来的xml标签封装成BeanDefinition对象
       */
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      // 3. 预准备工厂,给容器中注册了环境信息作为单实例Bean  方便后续自动装配
      // 并且放了一些后置处理器(监听、xxxAware功能)
      prepareBeanFactory(beanFactory);

      try {
         //  Allows post-processing of the bean factory in context subclasses.
         // 4. 留给子类的模板方法,允许子类继续对工厂执行一些处理
         postProcessBeanFactory(beanFactory);

         StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
         // Invoke factory processors registered as beans in the context.
         // 5. 【大核心】工厂增强:执行所有的BeanFactory 后置增强器 利用BeanFactory后置增强器对工厂进行修改或增强
         // 配置类ConfigurationClassPostProcessor也会在这个解析
         // BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor 完成对这两个接口的调用
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         // 6. 【核心】注册 所有的Bean的后置处理器
         registerBeanPostProcessors(beanFactory);
         beanPostProcess.end();

         // Initialize message source for this context.
         // 7. 初始化国际化组件
         initMessageSource();

         // Initialize event multicaster for this context.
         // 8. 初始化事件派发 功能
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         // 9. 留给子类继续增强处理逻辑
         // 这个方法着重理解模板设计模式,因为在springboot中,这个方法是用来做内嵌tomcat启动的
         onRefresh();

         // Check for listener beans and register them.
         // 10. 注册事件监听器,从容器中获取所有的ApplicationListener
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         /**
          * 11. 【大核心】bean创建:完成BeanFactory 初始化(工厂里面所有的组件都好了)
          *        这个方法一定要理解要具体看
          *        11.1、bean实例化过程
          *        11.2、ioc
          *        11.3、注解支持
          *        11.4、BeanPostProcessor的执行
          *        11.5、Aop的入口
          */
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         // 12. 发布事件
         finishRefresh();
      }
      ...
      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
         contextRefresh.end();
      }
   }
}
复制代码

Ce qui suit résume brièvement les étapes d'initialisation ci-dessus :

  1. prepareRefresh: Travaux préparatoires avant l'initialisation, tels que la préparation et la vérification des propriétés système ou des variables d'environnement. Dans certains cas, l'utilisation du projet nécessite de lire certaines variables système, puis au démarrage, les paramètres peuvent être vérifiés en préparant la fonction.
  2. obtainFreshBeanFactory: Initialise la BeanFactory et lit le fichier XML (si nécessaire). La fonction fournie après cette étape ApplicationContext就具有BeanFactory, c'est-à-dire que les opérations de base telles que l'extraction de bean peuvent être effectuées.
  3. prepareBeanFactory: Remplissez la BeanFactory avec diverses fonctions.
  4. postProcessBeanFactory: Effectuez un traitement supplémentaire sur BeanFactory. Non implémenté par défaut
  5. invokeBeanFactoryPostProcessors: active divers processeurs BeanFactory (appelant divers BeanFactoryPostProcessor). La chose la plus importante est ConfigurationClassPostProcessorque l'analyse de la classe de configuration est terminée ici et que la BeanDefinition du bean injecté dans le conteneur est générée.
  6. registerBeanPostProcessors: Enregistre et crée un gestionnaire de bean qui intercepte la création de bean. BeanPostProcessorA cette étape, la création est terminée.
  7. initMessageSource: Initialiser la source du message pour le contexte, c'est-à-dire internationaliser le corps du message dans différentes langues
  8. initApplicationEventMulticaster: Initialiser l'application diffuseur de messages et le mettre dans "applicationEventMulticaster"le bean
  9. onRefresh: laissé aux sous-classes pour initialiser d'autres beans
  10. registerListeners: Trouvez le bean écouteur dans tous les beans enregistrés et enregistrez-vous auprès du diffuseur de messages
  11. finishBeanFactoryInitialization :初始化剩下的实例(非惰性),在这里调用了getBean方法,创建了非惰性的bean实例
  12. finishRefresh :完成刷新过程,通知生命周期处理器 lifecycleProcesseor 刷新过程,同时发出ContextRefreshEvent 通知别人。

1. 准备环境 - prepareRefresh()

prepareRefresh() 方法整体还是比较清晰的,作用就是初始化一些状态和属性,为后面的工作做准备。具体代码如下:

protected void prepareRefresh() {
   // Switch to active.
   // 设置启动时间,激活刷新状态
   this.startupDate = System.currentTimeMillis();
   this.closed.set(false);
   this.active.set(true);

   if (logger.isDebugEnabled()) {
      if (logger.isTraceEnabled()) {
         logger.trace("Refreshing " + this);
      }
      else {
         logger.debug("Refreshing " + getDisplayName());
      }
   }

   // Initialize any placeholder property sources in the context environment.
   // 其他子容器自行实现,留给子类覆盖
   initPropertySources();

   // Validate that all properties marked as required are resolvable:
   // see ConfigurablePropertyResolver#setRequiredProperties
   // 准备环境变量信息
   getEnvironment().validateRequiredProperties();

   // Store pre-refresh ApplicationListeners...
   // 存储子容器早期运行的一些监听器
   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...
   this.earlyApplicationEvents = new LinkedHashSet<>();
}
复制代码

这里需要注意的两个方法:

  • initPropertySources() :这个方法是为了给用户自己实现初始化逻辑,可以初始化一些属性资源。因此Spring并没有实现这个方法。
  • validateRequiredProperties() :这个方法是对一些启动必须的属性的验证。

我们可以通过实现或者继承 ApplicationContext 来重写这两个方法,从而完成一些基本属性的校验。

2. 加载BeanFactory - obtainFreshBeanFactory()

obtainFreshBeanFactory() 从字面意思就是获取BeanFactory。经过这个方法,BeanFactory 就已经被创建完成。具体代码如下:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   // 刷新BeanFactory,注解模式下就是准备工厂,xml模式下会解析xml
   refreshBeanFactory();
   return getBeanFactory();
}
复制代码

而实际上将 BeanFactory的创建委托给了 refreshBeanFactory() 方法,refreshBeanFactory() 方法被两个类实现AbstractRefreshableApplicationContextGenericApplicationContext。继承图如下: image.png

对于注解版AnnotationConfigApplicationContext,我们看GenericApplicationContext.refreshBeanFactory() 的实现如下:

protected final void refreshBeanFactory() throws IllegalStateException {
        // CAS 设置将刷新状态置为 true
        if (!this.refreshed.compareAndSet(false, true)) {
                throw new IllegalStateException(
                                "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        }
        // 设置序列id
        this.beanFactory.setSerializationId(getId());
}

...
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
        return this.beanFactory;
}
复制代码

这里可以看到,GenericApplicationContext 中的实现非常简单。只是简单的将刷新状态置为true。 需要注意的是 this.beanFactory 的实际类型为 DefaultListableBeanFactory。在GenericApplicationContext 的构造函数中进行了对象创建或指定。如下:

public GenericApplicationContext() {
   this.beanFactory = new DefaultListableBeanFactory();
}
复制代码

对于xml配置版ClassPathXmlApplicationContext,我们看AbstractRefreshableApplicationContext.refreshBeanFactory():

@Override
protected final void refreshBeanFactory() throws BeansException {
   //如果BeanFactory不为空,则清除BeanFactory和里面的实例
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      // 1.创建DefaultListableBeanFactory
      // BeanFactory 实例工厂
      // 创建保存所有Bean定义信息的档案馆
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());

      // 2.设置是否可以循环依赖 allowCircularReferences
      //是否允许使用相同名称重新注册不同的bean实现.
      customizeBeanFactory(beanFactory);

      // 3.解析xml,并把xml中的标签封装成BeanDefinition对象
      // 加载所有bean定义的信息
      loadBeanDefinitions(beanFactory);
      this.beanFactory = beanFactory;
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}
复制代码

具体xml配置文件详细解析过程,请参见Spring5源码4-XML配置文件解析

3. 功能扩展 - prepareBeanFactory()

prepareBeanFactory()beanFactry 做了一些准备工作,设置了一些属性来扩展功能。

我们这里看 AbstractApplicationContext#prepareBeanFactory 的实现。具体代码如下:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   // 设置当前beanFactory 的classLoader 为当前context 的classLoader
   beanFactory.setBeanClassLoader(getClassLoader());
   // todo el表达式解析
   // 设置beanFactory 的表达式语言处理器,Spring3 增加了表达式语言的支持
   // 默认可以使用 #{bean.xxx}的形式来调用处理相关属性。
   if (!shouldIgnoreSpel) { // 解析器模式
      beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   }
   // 为beanFactory 增加一个默认的propertyEditor,这个主要是针对bean的属性等设置管理的一个工具
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // Configure the bean factory with context callbacks.
   // 添加一些后置处理器
   // 判断当前组件是否实现xxxAware接口,准备一个处理Aware接口的后置处理器
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   // 先忽略这些
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

   // BeanFactory interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   // 注册可以解析到的依赖,设置了几个自动装配的特殊规则
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Register early post-processor for detecting inner beans as ApplicationListeners.
   // 容器监听探测器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   // 增加对 AspectJ的支持
   if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   // 注册默认的组件,以下的组件都会注册到beanFactory中
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
   if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
      beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
   }
}
复制代码

上面函数中主要对几个方面进行了扩展:

  • 增加 SpEL 语言的支持
  • 增加对属性编辑器的支持
  • 增加对一些内置类,比如 EnvironmentAware、EmbeddedValueResolverAware等。
  • 设置了依赖功能可忽略的接口
  • 注册一些固定依赖的属性
  • 增加 AspectJ 的支持
  • 将相关环境变量及属性注册以单例模式注册

3.1. SpEL 的支持

SpEL 使用 #{…} 作为界定符,所有在大括号里面的字符都被认为是SpEL,使用格式如下:

    <bean id="demoB" name="demoB" class="com.kingfish.springbootdemo.replace.DemoB">
        <property name="demoA" value="#{demoA}"/>
    </bean>
复制代码

相当于

    <bean id="demoA" name="demoA" class="com.kingfish.springbootdemo.replace.DemoA" >
    </bean>
    <bean id="demoB" name="demoB" class="com.kingfish.springbootdemo.replace.DemoB">
        <property name="demoA" value="#{demoA}"/>
    </bean>
复制代码

在上面的代码中可以通过如下的代码注册语言解析器,就可以对SpEL 进行解析了。

beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
复制代码

其解析过程是在 bean 初始化的属性注入阶段(AbstractAutowireCapableBeanFactory#populateBean) 中调用了 applyPropertyValues(beanName, mbd, bw, pvs); 方法。在这个方法中,会通过构造BeanDefinitionValueResolver 类型实例 valueResolver 来进行属性值的解析,同时也是在这个步骤中一般通过 AbstractBeanFactory 中的 evaluateBeanDefinitionString 方法完成了SpEL的解析。

protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
        if (this.beanExpressionResolver == null) {
                return value;
        }

        Scope scope = null;
        if (beanDefinition != null) {
                String scopeName = beanDefinition.getScope();
                if (scopeName != null) {
                        scope = getRegisteredScope(scopeName);
                }
        }
        return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}
复制代码

当调用这个方法时会判断 是否存在语言解析器,如果存在则调用语言解析器的方法进行解析,解析的过程是在 Spring的expression 的包内,应用语言解析器的调用主要是在解析依赖注册bean 的时候,以及在完成bean的初始化和属性获取后进行属性填充的时候。

4. postProcessBeanFactory

AbstractApplicationContext#postProcessBeanFactory 并没有实现。如下

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

}
复制代码

而在Springboot2.x 版本中,其实现如下: AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.postProcessBeanFactory(beanFactory);
        // 扫描 指定 目录下的bean并注册
        if (this.basePackages != null && this.basePackages.length > 0) {
                this.scanner.scan(this.basePackages);
        }
        // 扫描指定注解下的bean 并注册
        if (!this.annotatedClasses.isEmpty()) {
                this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
        }
}
复制代码

需要注意的是 basePackagesannotatedClasses 默认都为空。即如果需要执行这一段逻辑,我们需要在指定 basePackagesannotatedClasses 后重新刷新容器。

5. 激活 BeanFactory 的后处理器 -invokeBeanFactoryPostProcessors

BeanFactory 作为Spring中容器功能的基础,用于存放所有已经加载的bean,为了保证程序的可扩展性,Spring 针对BeanFactory 做了大量的扩展,如PostProcessor。

这一步的功能主要是激活各种 BeanFactoryPostProcessors。

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
复制代码

对这块的解析,详见Spring5源码5-Bean生命周期后置处理器

6. BeanPostProcessor 的注册 - registerBeanPostProcessors

这一部分的部分叙述内容和 invokeBeanFactoryPostProcessors 的分析有关联,建议看完 invokeBeanFactoryPostProcessors 方法的分析再来看此部分。

下面来看看代码:

public static void registerBeanPostProcessors(
      ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

   // 获取到容器中所有的BeanPostProcessor, Bean的后置处理器
   String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

   // Register BeanPostProcessorChecker that logs an info message when
   // a bean is created during BeanPostProcessor instantiation, i.e. when
   // a bean is not eligible for getting processed by all BeanPostProcessors.
   int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
   // BeanPostProcessorChecker 是一个普通的信息打印
   //可能会有些情况当Spring 的配置中的后处理器还没有被注册就已经开始了bean的实例化,便会打印出BeanPostProcessorChecker 中设定的信息
   beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

   // Separate between BeanPostProcessors that implement PriorityOrdered,
   // Ordered, and the rest.
   // 保存实现了PriorityOrderd 接口的 后处理器
   List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
   // 保存MergedBeanDefinitionPostProcessor 后处理器
   List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
   // 保存实现了Orderd 接口的 后处理器
   List<String> orderedPostProcessorNames = new ArrayList<>();
   // 保存没有实现任何排序接口的后处理器
   List<String> nonOrderedPostProcessorNames = new ArrayList<>();
   // 按照规则筛选出不同的后处理器保存到集合中
   for (String ppName : postProcessorNames) {
      // 获取所有实现了PriorityOrdered接口
      if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
         BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
         priorityOrderedPostProcessors.add(pp);
         if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
         }
      }
      else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
         orderedPostProcessorNames.add(ppName);
      }
      else {
         nonOrderedPostProcessorNames.add(ppName);
      }
   }

   // First, register the BeanPostProcessors that implement PriorityOrdered.
   // 首先,注册实现了PriorityOrdered 接口的 BeanPostProcessor
   sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
   registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

   // Next, register the BeanPostProcessors that implement Ordered.
   // 接下来,注册实现了Ordered 接口的 BeanPostProcessor
   List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
   for (String ppName : orderedPostProcessorNames) {
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      orderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
         internalPostProcessors.add(pp);
      }
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   registerBeanPostProcessors(beanFactory, orderedPostProcessors);

   // Now, register all regular BeanPostProcessors.
   // 最后,注册了普通的BeanPostProcessor
   List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
   for (String ppName : nonOrderedPostProcessorNames) {
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      nonOrderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
         internalPostProcessors.add(pp);
      }
   }
   registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

   // Finally, re-register all internal BeanPostProcessors.
   // 最后,注册所有内部的BeanPostProcessors
   sortPostProcessors(internalPostProcessors, beanFactory);
   // 这里并不是重复注册, registerBeanPostProcessors 方法会先移除已存在的 BeanPostProcessor 随后重新加入。
   registerBeanPostProcessors(beanFactory, internalPostProcessors);

   // Re-register post-processor for detecting inner beans as ApplicationListeners,
   // moving it to the end of the processor chain (for picking up proxies etc).
   // 重新注册一下  ApplicationListenerDetector 这个后置处理器
   // 把 它放到后置处理器的最后一个位置
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
复制代码

相较于invokeBeanFactoryPostProcessors 方法,这里并没有考虑打硬编码的后处理器的顺序问题。其原因在于invokeBeanFactoryPostProcessors 中不仅要实现BeanFactoryPostProcessor的注册功能,还需要完成激活(执行对应方法)操作,所以需要载入配置中的定义并进行激活。而对于BeanPostProcessor 并不需要马上调用,并且硬编码方式实现的功能是将后处理器提取并调用,这里了并不需要调用,所以不需要考虑硬编码问题。这里只需要将配置文件中的BeanPostProcessor 创建之后出来并注册进行BeanFactory 中即可。需要注意 : 这里虽然没有调用 BeanPostProcessor,但是 BeanPostProcessor 的实例已经通过 beanFactory.getBean 创建完成。

7. 初始化消息资源 -initMessageSource

这里的作用很明显就是提取配置中定义的MessageSource,并将其记录在Spring容器中,也就是AbstractApplicationContext中。如果用户没有设置资源文件,Spring提供了默认的配置 DelegatingMessageSource

代码逻辑也很简单:在这里Spring 通过 beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); 来获取名称为 MESSAGE_SOURCE_BEAN_NAME (messageSource) 的bean作为 资源文件。这里也体现出了Spring “约束大于规定”的原则。

protected void initMessageSource() {
   // 注册 MessageSource 国际化组件
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
      // 获取自定义资源文件。这里可以看出使用了硬编码,默认资源文件为messageSource,否则便获取不到自定义配置资源
      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
      // Make MessageSource aware of parent MessageSource.
      if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
         HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
         if (hms.getParentMessageSource() == null) {
            // Only set parent context as parent MessageSource if no parent MessageSource
            // registered already.
            hms.setParentMessageSource(getInternalParentMessageSource());
         }
      }
      if (logger.isTraceEnabled()) {
         logger.trace("Using MessageSource [" + this.messageSource + "]");
      }
   }
   else {
      // Use empty MessageSource to be able to accept getMessage calls.
      // 如果用户没有配置,则使用默认的的资源文件
      DelegatingMessageSource dms = new DelegatingMessageSource();
      dms.setParentMessageSource(getInternalParentMessageSource());
      this.messageSource = dms;
      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
      }
   }
}
复制代码

8. 初始化事件监听 - initApplicationEventMulticaster

initApplicationEventMulticaster 的方法比较简单,考虑了两种情况:

  • 如果用户自定义了事件广播器,在使用用户自定义的事件广播器
  • 如果用户没有自定义事件广播器,则使用默认的 ApplicationEventMulticaster
// 如果用户自定义了事件广播器,在使用用户自定义的事件广播器
// 如果用户没有自定义事件广播器,则使用默认的 ApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
   // 注册 ApplicationEventMulticaster 组件
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   // 如果用户自定义了事件广播器,则使用用户自定义
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isTraceEnabled()) {
         logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }
   // 否则使用默认的事件广播器 SimpleApplicationEventMulticaster
   else {
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
               "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
      }
   }
}
复制代码

SimpleApplicationEventMulticaster 中有一段代码如下,可以看到,当Spring事件产生的时候,默认会使用SimpleApplicationEventMulticaster#multicastEvent 方法来广播事件,遍历所有的监听器,并使用监听器中的 onApplicationEvent 方法来进行监听事件的处理(通过 invokeListener 方法激活监听方法)。而对于每个监听器来说,其实都可以获取到产生的事件,但使用进行处理由监听器自己决定。

// 事件派发 可以是异步的
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   Executor executor = getTaskExecutor();
   // 观察者模式,把所有事件监听器拿来,调用他们的onApplicationEvent()即可
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}
复制代码

9. onRefresh();

onRefresh();留给子类实现。

protected void onRefresh() throws BeansException {
   // For subclasses: do nothing by default.
}
复制代码

在SpringBoot 中会刷新 调用 ServletWebServerApplicationContext#onRefresh 方法。

protected void onRefresh() {
        super.onRefresh();
        try {
                createWebServer();
        }
        catch (Throwable ex) {
                throw new ApplicationContextException("Unable to start web server", ex);
        }
}
复制代码

其中 super.onRefresh(); 调用了 GenericWebApplicationContext 中的实现也就是初始化一下主题资源。

@Override
protected void onRefresh() {
        this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
复制代码

但是在 createWebServer(); 中会启动Tomcat服务器

private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = getServletContext();
        if (webServer == null && servletContext == null) {
                // 获取 webServer 工厂类,因为webServer 的提供者有多个:JettyServletWebServerFactory、TomcatServletWebServerFactory、UndertowServletWebServerFactory
                ServletWebServerFactory factory = getWebServerFactory();
                // 获取webserver。其中启动了tomcat
                this.webServer = factory.getWebServer(getSelfInitializer());
        }
        else if (servletContext != null) {
                try {
                        getSelfInitializer().onStartup(servletContext);
                }
                catch (ServletException ex) {
                        throw new ApplicationContextException("Cannot initialize servlet context", ex);
                }
        }
        // 初始化资源
        initPropertySources();
}
复制代码

10. 注册监听器 - registerListeners()

注册监听器的方法实现非常简单,分为如下几步:

  • 注册硬编码注册的监听器
  • 注册配置注册的监听器
  • 发布早先的监听事件

具体代码如下:

/**
 * Add beans that implement ApplicationListener as listeners.
 * Doesn't affect other listeners, which can be added without being beans.
 * 多播器 和监听器 是观察者模式,里面包含了所有的监听器
 */
protected void registerListeners() {
   // 把所有监听器保存到多播器的集合中
   // Register statically specified listeners first.
   // 硬编码方式注册的监听器处理
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      // 保存到多播器中
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let post-processors apply to them!
   // 获取ApplicationListener 在ioc容器中注册的bean的名字
   // 配置文件注册的监听处理器
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      // 获取所有的监听器,并保存他们的名字在
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }

   // Publish early application events now that we finally have a multicaster...
   // 派发之前的一些早期事件
   // 发布之前保存的需要发布的事件
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         // todo
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}
复制代码

11. BeanFactory的收尾工作 - finishBeanFactoryInitialization

这一步的目的是 结束BeanFactory 的初始化工作,其中包括如下几步 :

对 ConversionService 的设置。通过 ConversionService 的配置可以很轻松完成一些类型转换工作。 冻结所有的bean定义 。到这一步,也就说所有的bean定义已经定型了,不可被修改了,也正式可以缓存bean的元数据了。 初始化剩下的非惰性单实例。ApplicationContext 实现的默认行为就是启动时将所有单例 bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的单例bean。而这个实例化的过程就是在 preInstantiateSingletons 中完成的。 关于 getBean 方法的逻辑,请阅 Spring 源码分析三 :bean的加载① - doGetBean概述

代码如下:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // Initialize conversion service for this context.
   // 1. 对 ConversionService 的设置
   // 如果 BeanFactory 中加载了beanName 为 ConversionService 的bean,并且类型是 ConversionService。那么将其设置为 conversionService
   // 给工厂设置好conversionService 【负责类型转换的组件服务】
   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 BeanFactoryPostProcessor
   // (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   // 注册一个默认的值解析器("${}")
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }

   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
   // 按照类型获取LoadTimeWeaverAware组件;加载时织入功能【aop】 使用不多
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   // 开始调用 getBean 方法初始化LoadTimeWeaverAware
   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.
   // 2. 冻结所有的bean定义,说明注册的bean定义将不被修改或任何进一步的处理
   beanFactory.freezeConfiguration();

   // Instantiate all remaining (non-lazy-init) singletons.
   // todo 3. 初始化所有 非懒加载的单实例的bean
   beanFactory.preInstantiateSingletons();
}
复制代码

这里我们需要特别关注一下 DefaultListableBeanFactory#preInstantiateSingletons,在这里面,容器创建了所有的非惰性单实例。(之所以不创建原型bean,是因为原型bean没必要进行缓存,每次使用直接创建即可)

@Override
public void preInstantiateSingletons() throws BeansException {
   if (logger.isTraceEnabled()) {
      logger.trace("Pre-instantiating singletons in " + this);
   }

   // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   // 获取所有 beanName
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   // 创建出所有的单实例bean
   for (String beanName : beanNames) {
      // 获取合并后的 BeanDefinition
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      // 单实例 & 非抽象&不是懒加载
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         // 如果是FactoryBean
         if (isFactoryBean(beanName)) {
            // 如果是 Factorybean 则 拼接 & 前缀获取bean
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
               // 判断是否要立即初始化Bean。对于 FactoryBean,可能并不需要立即初始化其getObject 方法代理的对象。
               FactoryBean<?> factory = (FactoryBean<?>) bean;
               boolean isEagerInit;
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                  isEagerInit = AccessController.doPrivileged(
                        (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
               }
               else {
                  isEagerInit = (factory instanceof SmartFactoryBean &&
                        ((SmartFactoryBean<?>) factory).isEagerInit());
               }
               // 如果需要立即初始化,则初始化bean
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         // 不是FactoryBean则执行这个逻辑,普通的单实例非懒加载bean的创建
         else {
            // todo
            getBean(beanName);
         }
      }
   }

   // Trigger post-initialization callback for all applicable beans...
   // todo 后置处理器 SmartInitializingSingleton.afterSingletonsInstantiated()方法
   // 触发所有适用bean的初始化后回调。 这里实际上是触发 SmartInitializingSingleton#afterSingletonsInstantiated 方法
   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
               .tag("beanName", beanName);
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         }
         else {
            smartSingleton.afterSingletonsInstantiated();
         }
         smartInitialize.end();
      }
   }
}
复制代码

对于bean的创建和初始化,详见# Spring5源码7-Bean创建及初始化(上)
# Spring5源码7-Bean创建及初始化(下)

12. 完成刷新 - finishRefresh()

在 Spring 中还提供了 Lifecycle 接口,Lifecycle 接口包含 start、stop 方法,实现此接口后Spring会保证在启动的时候调用其 start 方法开始生命周期,并在Spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对MQ进行轮询等)。而ApplicationContext 的初始化最后证实保证了这一功能的实现。

protected void finishRefresh() {
   // Clear context-level resource caches (such as ASM metadata from scanning).
   // 清除资源缓存
   clearResourceCaches();

   // Initialize lifecycle processor for this context.
   // 注册  LifecycleProcessor 组件
   // 当Application 启动或停止时,会通过 LifecycleProcessor 来与所有声明的bean周期做状态更新,
   // 而在LifecycleProcessor 的使用前首先需要初始化,这里进行了LifecycleProcessor  的初始化。
   initLifecycleProcessor();

   // Propagate refresh to lifecycle processor first.
   // 告诉LifecycleProcessor容器  onRefresh中
   getLifecycleProcessor().onRefresh();

   // Publish the final event.
   // 发布事件
   // 当完成ApplicationContext 初始化的时候,要通过Spring 中的事件发布机制来发出ContextRefreshedEvent 的事件,以保证对应的监听器可以做进一步的逻辑处理。
   publishEvent(new ContextRefreshedEvent(this));

   // Participate in LiveBeansView MBean, if active.
   // jconsole (暴露MBean端点信息)
   // 注册 ApplicationContext
   if (!NativeDetector.inNativeImage()) {
      LiveBeansView.registerApplicationContext(this);
   }
}
复制代码

13. refresh流程图(注解版)

image.png image.png

参考文章

Adresse github d'annotation du code source Spring5
Analyse approfondie du code source Spring (2e édition)
Analyse du code
source Spring Notes d'analyse approfondie
du code source Spring Annotation Spring et analyse du code source
Développement basé sur les annotations Spring Tutoriel de la station B

Je suppose que tu aimes

Origine juejin.im/post/7135998409135095816
conseillé
Classement