深入剖析Spring boot自动装配原理二(@Import)

前言

关于@Import注解的使用,在Spring源码中随处可见,其作用大家基本也都知道,无非就是注入指定的Bean到Spring IOC容器管理,只能作用用于类上,其用法分三种:普通的类直接注入、实现了ImportSelector接口的类、实现了ImportBeanDefinitionRegistrar接口的类,那么Spring具体是如何实现的?这三种方式又有何不同?一起跟进源码一探究竟,彻底了解Import的实现。

源码追踪(Spring版本:5.3.6-SNAPSHOT

众所周知Spring需要先初始化上下文容器,Spring上下文容器针对不同的场景设计了较多类型,不过都大同小异,这里拿其中的AnnotationConfigApplicationContext进行讲解,如果需要进一步了解Spring的每一个容器或者Spring的更多源码细节,可关注我,我会在后面的章节中逐步揭开Spring源码迷雾。

您的认可是我前进的动力,如果您觉得可以请关注我并转发文章,谢谢!!!

AnnotationConfigApplicationContext(AbstractApplicationContext)

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {

  // 注解配置上下文初始化

  this();

  // 将配置组件(AppConfig)注册到AnnotationConfigApplicationContext上下文对象的beanFactory中(即将bean信息放入beanDefinitionMap中)

  register(componentClasses);

  // 刷新注册到AnnotationConfigApplicationContext上下文对象的相关属性

  refresh();

}

@Override

// AbstractApplicationContext公共方法

public void refresh() throws BeansException, IllegalStateException {

  synchronized (this.startupShutdownMonitor) {

      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

      // Prepare this context for refreshing.

      prepareRefresh();

      // 刷新AnnotationConfigApplicationContext上下文对象的BeanFactory并返回BeanFactory对象

      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.

      prepareBeanFactory(beanFactory);

      try {

        // Allows post-processing of the bean factory in context subclasses.

        postProcessBeanFactory(beanFactory);

        StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

        // 实例化并调用所有已注册的BeanFactoryPostProcessor的Bean到Spring容器中.

        invokeBeanFactoryPostProcessors(beanFactory);

    ......

        // 实例化所有BeanFactory中非延迟加载的Bean.

        finishBeanFactoryInitialization(beanFactory);

        // Last step: publish corresponding event.

        finishRefresh();

      }

    ......

}

PostProcessorRegistrationDelegate

public static void invokeBeanFactoryPostProcessors(

      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

  ......

      // Do not initialize FactoryBeans here: We need to leave all regular beans

      // uninitialized to let the bean factory post-processors apply to them!

      // Separate between BeanDefinitionRegistryPostProcessors that implement

      // PriorityOrdered, Ordered, and the rest.

      List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

      // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.

      // 获取BeanDefinitionRegistryPostProcessor类型的bean名称,注意这里获取到了名字为

      // org.springframework.context.annotation.internalConfigurationAnnotationProcessor的bean

      // (这个bean不是直接存在的,在AnnotationConfigUtils类中可查到其对应的Ben为ConfigurationClassPostProcessor)

      String[] postProcessorNames =

            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

      for (String ppName : postProcessorNames) {

        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {

            // beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)获取到ConfigurationClassPostProcessor

            // 将ConfigurationClassPostProcessor添加到当前注册Bean的处理对象集合

            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

            processedBeans.add(ppName);

        }

      }

      // 将BeanDefinitionRegistryPostProcessor排序

      sortPostProcessors(currentRegistryProcessors, beanFactory);

      // 将BeanDefinitionRegistryPostProcessor稍后注册到BeanFactory

      registryProcessors.addAll(currentRegistryProcessors);

      //

      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());

      currentRegistryProcessors.clear();

      ......

}

通过调用PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors方法循环执行所有BeanDefinitionRegistryPostProcessor,将相关Bean注入BeanFacotry。这里通过调用ConfigurationClassPostProcessor 处理所有@Configuration配置类,其通过核心方法processConfigBeanDefinitions来处理相关Bean的注入。

ConfigurationClassPostProcessor

@Override

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

  // 生成处理ID

  int factoryId = System.identityHashCode(beanFactory);

  // 判断后置处理器在registriesPostProcessed和factoriesPostProcessed中有没有被调用过

  if (this.factoriesPostProcessed.contains(factoryId)) {

      throw new IllegalStateException(

            "postProcessBeanFactory already called on this post-processor against " + beanFactory);

  }

  // 调用前保存factoryId,防止被重复调用

  this.factoriesPostProcessed.add(factoryId);

  if (!this.registriesPostProcessed.contains(factoryId)) {

      // 注入标有@configuration的Bean里面需要注入的类(如:@Import注解)

      processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);

  }

  enhanceConfigurationClasses(beanFactory);

  beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));

}

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

  // 需要处理的候选@configuration类

  List<BeanDefinitionHolder> configCandidates = new ArrayList<>();

  // 获取BeanFactory中注入的所有beanDefinitionNames

  String[] candidateNames = registry.getBeanDefinitionNames();

  for (String beanName : candidateNames) {

      BeanDefinition beanDef = registry.getBeanDefinition(beanName);

      // 检查当前Bean是否已当作配置类处理过

      if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {

        if (logger.isDebugEnabled()) {

            logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);

        }

      }

      // 检查当前Bean是否是配置类,如果是则添加到configCandidates中,后面进行处理

      else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {

        configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));

      }

  }

  // Return immediately if no @Configuration classes were found

  if (configCandidates.isEmpty()) {

      return;

  }

  ......

  // 准备解析 @Configuration 标注的类,构建解析对象

  ConfigurationClassParser parser = new ConfigurationClassParser(

        this.metadataReaderFactory, this.problemReporter, this.environment,

        this.resourceLoader, this.componentScanBeanNameGenerator, registry);

  // 配置Bean去重

  Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);

  // 存储已解析过的配置类

  Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());

  // 循环解析

  do {

      StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");

      // 解析所有@Configuration标记Bean,并将解析的Bean信息存入ConfigurationClassParser的configurationClasses集合中

      parser.parse(candidates);

      parser.validate();

      Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());

      configClasses.removeAll(alreadyParsed);

      // Read the model and create bean definitions based on its content

      if (this.reader == null) {

        this.reader = new ConfigurationClassBeanDefinitionReader(

              registry, this.sourceExtractor, this.resourceLoader, this.environment,

              this.importBeanNameGenerator, parser.getImportRegistry());

      }

      // 初始化所有配置类中的Bean(包含处理ImportBeanDefinitionRegistrars类),

      // 并将其放入Spring容器中(BeanFactory的beanDefinitionMap)

      this.reader.loadBeanDefinitions(configClasses);

      alreadyParsed.addAll(configClasses);

      processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

      candidates.clear();

      ......

  }

  while (!candidates.isEmpty());

  ......

}

通过调用ConfigurationClassParser#parse对@Configuration类进行解析。

ConfigurationClassParser

public void parse(Set<BeanDefinitionHolder> configCandidates) {

  for (BeanDefinitionHolder holder : configCandidates) {

      BeanDefinition bd = holder.getBeanDefinition();

      try {

        if (bd instanceof AnnotatedBeanDefinition) {

            // Configuration类为AnnotatedBean

            parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());

        }

        else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {

            parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());

        }

        else {

            parse(bd.getBeanClassName(), holder.getBeanName());

        }

      }

      ......

  }

  this.deferredImportSelectorHandler.process();

}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {

  processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);

}

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {

  // 判断是否需要跳过该配置类的解析(例如配置了@Conditional注解)

  if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {

      return;

  }

  // 标识该配置类是否解析过

  ConfigurationClass existingClass = this.configurationClasses.get(configClass);

  ......

  // Recursively process the configuration class and its superclass hierarchy.

  // 将配置类转为SourceClass类

  SourceClass sourceClass = asSourceClass(configClass, filter);

  // 从当前配置类configClass开始向上沿着类继承结构逐层执行doProcessConfigurationClass,

// 直到遇到的父类是由Java提供的类结束循环

  do {

      sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);

  }

  while (sourceClass != null);

  this.configurationClasses.put(configClass, configClass);

}

@Nullable

protected final SourceClass doProcessConfigurationClass(

      ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)

      throws IOException {

    // Component注解存在继承关系,递归处理嵌套类

  if (configClass.getMetadata().isAnnotated(Component.class.getName())) {

      // Recursively process any member (nested) classes first

      processMemberClasses(configClass, sourceClass, filter);

  }

  ......

  // 重点来了,在这里处理Import注解

  processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

  ......

  // Process superclass, if any

  if (sourceClass.getMetadata().hasSuperClass()) {

      String superclass = sourceClass.getMetadata().getSuperClassName();

      if (superclass != null && !superclass.startsWith("java") &&

            !this.knownSuperclasses.containsKey(superclass)) {

        this.knownSuperclasses.put(superclass, configClass);

        // Superclass found, return its annotation metadata and recurse

        return sourceClass.getSuperClass();

      }

  }

  // No superclass -> processing is complete

  return null;

}

/**

  * 处理配置类上搜集到的@Import注解

  * @Param configuClass 配置类

  * @Param currentSourceClass 当前源码类

  * @Param importCandidates 所有的@Import注解的value

  * @Param exclusionFilter 需要排除的类

  * @Param checkForCircularImports 是否检查循环导入

  **/

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,

      Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,

      boolean checkForCircularImports) {

  if (importCandidates.isEmpty()) {

      return;

  }

  if (checkForCircularImports && isChainedImportOnStack(configClass)) {

      this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));

  }

  else {

      // 开始处理配置类configClass上@Import所有的importCandidates

      this.importStack.push(configClass);

      try {

          // 循环处理每一个@Import,每个@Import可能导入三种类型的类 :

          // 1. ImportSelector

          // 2. ImportBeanDefinitionRegistrar

          // 3. 其他类型,都当作配置类处理,也就是相当于使用了注解@Configuration的配置类

        // 下面的for循环中对这三种情况执行了不同的处理逻辑

        for (SourceClass candidate : importCandidates) {

            // 处理ImportSelector类(Spring Boot的自动装配采用的是这种方式)

            if (candidate.isAssignable(ImportSelector.class)) {

              // 加载对应的ImportSelector实现类

              Class<?> candidateClass = candidate.loadClass();

              // 实例化对应的实现ImportSelector的类

              ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,

                    this.environment, this.resourceLoader, this.registry);

              // 获取ImportSelector类中需要排除的实例化的类

              Predicate<String> selectorFilter = selector.getExclusionFilter();

              if (selectorFilter != null) {

                  exclusionFilter = exclusionFilter.or(selectorFilter);

              }

              // 后置处理类交由后置处理器进行处理,本类涵盖代码的第18行代码处理(this.deferredImportSelectorHandler.process();)

              if (selector instanceof DeferredImportSelector) {

                  this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);

              }

              else {

                  // 调用实现ImportSelector的类的selectImports,获取需要实例化类的className

                  String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());

                  // 从当前ImportSelector需要实例化的类开始向上沿着类继承结构逐层执行将className加入到BeanFactory的beanDefinitionMap中(要排除的类除外),

                // 直到遇到的父类是由Java提供的类结束循环

                  Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);

                  // 循环处理importClassNames类中再包含的import类

                  processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);

              }

            }

            else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {

              // Candidate class is an ImportBeanDefinitionRegistrar ->

              // delegate to it to register additional bean definitions

              Class<?> candidateClass = candidate.loadClass();

              // 直接实例化ImportBeanDefinitionRegistrar 类

              ImportBeanDefinitionRegistrar registrar =

                    ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,

                          this.environment, this.resourceLoader, this.registry);

              // 将ImportBeanDefinitionRegistrar 类加入到importBeanDefinitionRegistrars集合中

              // 会在ConfigurationClassPostProcessor第69行代码进行处理

              configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

            }

            else {

              // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->

              // process it as an @Configuration class

              this.importStack.registerImport(

                    currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());

              // 非ImportSelector or ImportBeanDefinitionRegistrar直接处理,放入BeanFactory中

              processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);

            }

        }

      }

      ......

  }

}

通过以上的步骤已将Import中的类注入到BeanFacotry的beanDefinitionMap中等待实例化(ImportBeanDefinitionRegistrar类型的Bean需要通过下面的方式处理才能放入),回到ConfigurationClassPostProcessor的69行代码(this.reader.loadBeanDefinitions(configClasses);),调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions进行处理。

ConfigurationClassBeanDefinitionReader

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {

  TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();

  for (ConfigurationClass configClass : configurationModel) {

      loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);

  }

}

private void loadBeanDefinitionsForConfigurationClass(

      ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

  ......

  loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

  // 获取所有ImportBeanDefinitionRegistrars进行处理

  loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());

}

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {

  registrars.forEach((registrar, metadata) ->

        // 调用继承ImportBeanDefinitionRegistrar类中的registerBeanDefinitions将Bean注入到BeanFactory

        registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));

}

到这一步Import的所有类已注册到BeanFactory中,那么什么时候对这些类进行初始化呢?回到AnnotationConfigApplicationContext(即AbstractApplicationContext)的refresh方法,通过finishBeanFactoryInitialization(beanFactory)实例化Bean。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容