栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Springboot @Import 详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Springboot @Import 详解

SpringBoot 的 @import 用于将指定的类实例注入之Spring IOC Container中。 

今天抽空在仔细看了下Springboot 关于 @import 的处理过程, 记下来以后看。

1. @import

先看Spring对它的注释 (文档贴过来的), 总结下来作用就是和xml配置的 标签作用一样,允许通过它引入 @Configuration 注解的类 (java config), 引入importSelector接口(这个比较重要, 因为要通过它去判定要引入哪些@Configuration) 和 importBeanDefinitionRegistrar 接口的实现, 也包括 @Component注解的普通类。

但是如果要引入另一个xml 文件形式配置的 bean, 则需要通过 @importResource 注解。


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface import {

  
  Class[] value();

}

2. importSelector

因为 @import 的实现有很多时候需要借助 importSelector 接口, 所以我们再看下这个接口的描述, 总结下来就是需要通过这个接口的实现去决定要引入哪些 @Configuration。 它如果实现了以下四个Aware 接口, 那么spring保证会在调用它之前先调用Aware接口的方法。

至于为什么要保证调用Aware, 我个人觉得应该是你可以通过这些Aware去感知系统里边所有的环境变量, 从而决定你具体的选择逻辑。


public interface importSelector {

  
  String[] selectimports(Annotationmetadata importingClassmetadata);

}

3. Springboot 对@import注解的处理过程

Springboot对注解的处理都发生在AbstractApplicationContext -> refresh() -> invokeBeanFactoryPostProcessors(beanFactory) -> ConfigurationClassPostProcessor -> postProcessBeanDefinitionRegistry()方法中。

(稍微说下也免得我自己忘了, springboot初始化的普通context(非web) 是AnnotationConfigApplicationContext, 在初始化的时候会初始化两个工具类, AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 分别用来从 annotation driven 的配置和xml的配置中读取beanDefinition并向context注册, 那么在初始化 AnnotatedBeanDefinitionReader 的时候, 会向BeanFactory注册一个ConfigurationClassPostProcessor 用来处理所有的基于annotation的bean, 这个ConfigurationClassPostProcessor 是 BeanFactoryPostProcessor 的一个实现,springboot会保证在  invokeBeanFactoryPostProcessors(beanFactory) 方法中调用注册到它上边的所有的BeanFactoryPostProcessor)

如下代码显示是通过 ConfigurationClassParser 类来转换的

// Parse each @Configuration class
    ConfigurationClassParser parser = new ConfigurationClassParser(
 this.metadataReaderFactory, this.problemReporter, this.environment,
 this.resourceLoader, this.componentScanBeanNameGenerator, registry);

那么在 ConfigurationClassParser -> processConfigurationClass() -> doProcessConfigurationClass() 方法中我们找到了 (这里边的流程还是很清楚的, 分别按次序处理了@PropertySource, @ComponentScan, @import, @importResource, 在处理这些注解的时候是通过递归处理来保证所有的都被处理了)

// Process any @import annotations
    processimports(configClass, sourceClass, getimports(sourceClass), true);

那接下来就看它到底是怎么做的 . 流程依然清晰 :

  首先, 判断如果被import的是 importSelector.class 接口的实现, 那么初始化这个被import的类, 然后调用它的selectimports方法去获得所需要的引入的configuration, 然后递归处理

  其次, 判断如果被import的是 importBeanDefinitionRegistrar 接口的实现, 那么初始化后将对当前对象的处理委托给这个importBeanDefinitionRegistrar (不是特别明白, 只是我的猜测)

  最后, 将import引入的类作为一个正常的类来处理 ( 调用最外层的doProcessConfigurationClass())

所以, 从这里我们知道, 如果你引入的是一个正常的component, 那么会作为@Compoent或者@Configuration来处理, 这样在BeanFactory里边可以通过getBean拿到, 但如果你是 importSelector 或者 importBeanDefinitionRegistrar 接口的实现, 那么spring并不会将他们注册到beanFactory中,而只是调用他们的方法。

private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass,
      Collection importCandidates, boolean checkForCircularimports) {

    if (importCandidates.isEmpty()) {
      return;
    }

    if (checkForCircularimports && isChainedimportonStack(configClass)) {
      this.problemReporter.error(new CircularimportProblem(configClass, this.importStack));
    }
    else {
      this.importStack.push(configClass);
      try {
 for (SourceClass candidate : importCandidates) {
   if (candidate.isAssignable(importSelector.class)) {
     // Candidate class is an importSelector -> delegate to it to determine imports
     Class candidateClass = candidate.loadClass();
     importSelector selector = BeanUtils.instantiateClass(candidateClass, importSelector.class);
     ParserStrategyUtils.invokeAwareMethods(
  selector, this.environment, this.resourceLoader, this.registry);
     if (this.deferredimportSelectors != null && selector instanceof DeferredimportSelector) {
this.deferredimportSelectors.add(
    new DeferredimportSelectorHolder(configClass, (DeferredimportSelector) selector));
     }
     else {
String[] importClassNames = selector.selectimports(currentSourceClass.getmetadata());
Collection importSourceClasses = asSourceClasses(importClassNames);
processimports(configClass, currentSourceClass, importSourceClasses, 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 registrar =
  BeanUtils.instantiateClass(candidateClass, importBeanDefinitionRegistrar.class);
     ParserStrategyUtils.invokeAwareMethods(
  registrar, this.environment, this.resourceLoader, this.registry);
     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());
     processConfigurationClass(candidate.asConfigClass(configClass));
   }
 }
      }
      catch (BeanDefinitionStoreException ex) {
 throw ex;
      }
      catch (Throwable ex) {
 throw new BeanDefinitionStoreException(
     "Failed to process import candidates for configuration class [" +
     configClass.getmetadata().getClassName() + "]", ex);
      }
      finally {
 this.importStack.pop();
      }
    }
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/139602.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号