千家信息网

SpringBoot如何解析配置类以及集成第三方配置

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,小编给大家分享一下SpringBoot如何解析配置类以及集成第三方配置,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Spr
千家信息网最后更新 2026年11月02日SpringBoot如何解析配置类以及集成第三方配置

小编给大家分享一下SpringBoot如何解析配置类以及集成第三方配置,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

SpringBoot作为Java领域非常流行的开源框架,集成了大量常用的第三方库配置,Spring Boot应用中这些第三方库几乎可以是零配置的开箱即用,大部分的 Spring Boot 应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。SpringBoot上手快,但是如果你的项目中业务场景需要一些特殊定制,甚至对源码进行定制化,那这时候了解原理就变成必需的了,只有充分了解源码,知道框架底层的工作原理,才能对源码中原有的机制进行修改 / 扩展等等。

一、基本概念介绍

在SpringBoot中推荐基于Java Config的方式来代替传统的XML方式去引入Bean,本文就是分析SpringBoot如何解析这些配置类,为容器中注入我们自定义的以及SpringBoot为我们提供的Bean。SpringBoot版本基于2.1.7.RELEASE。

// 通常一个SpringBoot工程会含有这样一个主配置类,它位于我们项目的根包下,通过启动这个main方法就可以启动我们的项目// 下面我们先分析@SpringBootApplication注解有哪些作用,在第二节中分析run方法,在run方法中会进行配置类的解析@SpringBootApplicationpublic class SpringbootApplication {    public static void main(String[] args) {       SpringApplication.run(SpringbootApplication.class, args);    }}
// 点击@SpringBootApplication进去发现它其实是由三个核心注解构成的,下面分别讲解这三个注解@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),                      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {

1、@SpringBootConfiguration注解

// 点进去发现它其实就是一个@Configuration注解,SpringBoot解析到就会知道这是一个配置类,会给容器中引入一些bean// 一个被@Configuration标注的类,相当于一个applicationContext.xml文件// @Configuration点进去发现其实就是一个@Component注解@Configurationpublic @interface SpringBootConfiguration {}

2、@EnableAutoConfiguration注解

// 结合下面@AutoConfigurationPackage注解,发现@EnableAutoConfiguration注解就是通过@Import注解给容器中引入了两个bean,// 分别是AutoConfigurationImportSelector和AutoConfigurationPackages.Registrar,通过这两个类可以给容器中引入更多的类// 下面先介绍下@Import注解的使用@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {}@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage {}

@Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; // 往容器中新增BeanDefinition GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(Chicken.class); registry.registerBeanDefinition("beanFactoryPostProcessor-Chicken", beanDefinition); // 修改容器中原有的BeanDefinition BeanDefinition snake = registry.getBeanDefinition("snake"); snake.setLazyInit(true); } }

@Componentpublic class CatBeanPostProcessor implements BeanPostProcessor {    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        return bean;    }    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        if (bean instanceof Cat){            Cat cat = (Cat) bean;            cat.setName("changeNameCat");        }        return bean;    }}

二、SpringBoot启动流程概述

第一节是SpringBoot解析自动配置类会用到的一些知识点,下面我们来看SpringBoot解析配置类的具体过程。上图是SpringBoot启动流程图,其中在refreshContext的第五步会调用容器的BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry方法。其中有一个是ConfigurationClassPostProcessor,它是在创建ConfigurableApplicationContext时设置到容器中的,如下所示。

// 图中说的创建ConfigurableApplicationContext,默认创建的是普通的Servlet Web容器,就是下面这个// 通过反射创建会走到其默认的构造函数public AnnotationConfigServletWebServerApplicationContext() {    // 这里面进去会走到下面代码    this.reader = new AnnotatedBeanDefinitionReader(this);    this.scanner = new ClassPathBeanDefinitionScanner(this);}// 走到这里registerAnnotationConfigProcessors(registry, null);// 走到这里// 向容器中注入一个ConfigurationClassPostProcessor,它是BeanFactoryPostProcessorif (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {    RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);    def.setSource(source);    beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}// 向容器中注入一个AutowiredAnnotationBeanPostProcessor,它是BeanPostProcessor,用于解决依赖注入的if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {    RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);    def.setSource(source);     beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}

三、配置类解析

上面说到在refreshContex中的第五步时,会调用容器中的BeanFactoryPostProcessor

的postProcessBeanDefinitionRegistry方法。其中有一个是ConfigurationClassPostProcessor,这是我们解析自动配置类的入口,下面分析其postProcessBeanDefinitionRegistry方法。

1、配置类解析流程概述

@Override  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {      // 删掉一些非关键代码    processConfigBeanDefinitions(registry);  }

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List configCandidates = new ArrayList<>(); // 获取容器中已注册的bean名字,见下图,注意,这里容器中这些BeanDefinition都是容器初始化过程中容器添加进去的 // 不是我们业务代码的beanDefinition,这段代码其实是连贯的,为了注释图片方便才分开 String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { // 获取BeanDefinition BeanDefinition beanDef = registry.getBeanDefinition(beanName); // 判断这个BeanDefinition的configurationClass属性是不是full或者lite,如果是认为已经处理过了,第一次时默认为空, // 走下面分支 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { // 打印日志记录下 } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { // 1) 下面先分析下这个checkConfigurationClassCandidate方法,这边看方法名也可以猜到是检测该类是不是配置类 // 是配置类的意思就是它会给容器中引入bean,这个方法判断主要就是看这个类的元信息中有没有@Configuration注解 // 有没有@Component注解、有没有@ComponentScan、@Import、@ImportResource注解,有没有@Bean方法 // 构造一个BeanDefinitionHolder,放入configCandidates中 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } // Return immediately if no @Configuration classes were found // 上图中容易默认已经引入了7个BeanDefinition,经过上面检测发现默认就一个符合条件的配置类,即我们的主配置类 // 这里面configCandidates就一个,就是SpringBootApplication if (configCandidates.isEmpty()) { return; } // Sort by previously determined @Order value, if applicable // 排序 configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // 删掉部分代码 // Parse each @Configuration class // 配置类解析工具 ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); // 待处理集合 Set candidates = new LinkedHashSet<>(configCandidates); // 已处理集合 Set alreadyParsed = new HashSet<>(configCandidates.size()); // 循环处理直到candidates.isEmpty() do { // 这边开始解析,对应步骤4 parser.parse(candidates); parser.validate(); // 取出第四步解析得到的一些configurationClasses集合 Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // 删除一部分代码 // 这边也会去加载BeanDefinition,对应图中步骤五 this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); } while (!candidates.isEmpty()); }

2、检测是否是配置类

在配置类解析流程图中,第二步,会获取容器中已经注册的BeanDefinition,放入candidateNames中,然后依次遍历这些BeanDefinition,判断它有没有被处理过,如果处理过就不管,否则通过checkConfigurationClassCandidate方法去判断它是不是配置类,判断方法如下。通过阅读这段代码,发现如果一个类上面有@Configuration注解、或者有@Component、@ComponentScan、@Import、@ImportResource注解、或者有@Bean标注的方法,则认为它是一个配置类。默认情况下,走到这里时最终只有一个candidateName符合,它是我们的主配置类,也就是SpringbootApplication这个Bean。

ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory);public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef,                                                        MetadataReaderFactory metadataReaderFactory) {        String className = beanDef.getBeanClassName();      // 获取下类名,如果类名为空或者该类为工厂类    if (className == null || beanDef.getFactoryMethodName() != null) {          return false;      }        // 获取类的元数据信息    AnnotationMetadata metadata;     // 上图的7个candidateNames中只有一个springbootApplication是AnnotatedBeanDefinition,其余全返回false    if (beanDef instanceof AnnotatedBeanDefinition &&                  className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {          // Can reuse the pre-parsed metadata from the given BeanDefinition...   // springbootApplication走到这里        metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();      }      else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {          // Check already loaded Class if present...          // since we possibly can't even load the class file for this Class.    Class beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();          metadata = new StandardAnnotationMetadata(beanClass, true);      }      else {          try {              MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);        // 读取类的元数据信息,这里面包括注解等信息            metadata = metadataReader.getAnnotationMetadata();          }          catch (IOException ex) {              return false;          }      }        // metadata.isAnnotated(Configuration.class.getName()),这个就是判断类上面有没有@Configuration注解    if (isFullConfigurationCandidate(metadata)) {    // 如果true的话设置下这个属性,那么就标记为处理过了        beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);      } else if (isLiteConfigurationCandidate(metadata)) {          beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);      }      else {    // 其余6个返回false        return false;      }        // It's a full or lite configuration candidate... Let's determine the order value, if any.      Integer order = getOrder(metadata);      if (order != null) {        // 获取下类上的@Order信息       beanDef.setAttribute(ORDER_ATTRIBUTE, order);      }      return true;  }
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {      // Do not consider an interface or an annotation...      if (metadata.isInterface()) {          return false;      }        // Any of the typical annotations found?      for (String indicator : candidateIndicators) {    // 判断下类上面有没有这几个注解        if (metadata.isAnnotated(indicator)) {             return true;          }      }        // Finally, let's look for @Bean methods...      try {          // 判断有没有@Bean的方法        return metadata.hasAnnotatedMethods(Bean.class.getName());      }      return false;    }  }private static final Set candidateIndicators = new HashSet<>();    static {      candidateIndicators.add(Component.class.getName());      candidateIndicators.add(ComponentScan.class.getName());      candidateIndicators.add(Import.class.getName());      candidateIndicators.add(ImportResource.class.getName());  }

3、步骤四解析

public void parse(Set configCandidates) {      // 删除部分代码,实际执行时这里的configCandidates就一个springBootApplication代表的主配置类    for (BeanDefinitionHolder holder : configCandidates) {        // 获取BeanDefinition        BeanDefinition bd = holder.getBeanDefinition();          // 我们的SpringBootApplication会走到这边,下面先分析这边        parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());     }      // (**)处这边也要留意下,这边会处理DeferredImportSelector,我们前面说的AutoConfigurationImportSelector就是在这边处理    // 给容器中导入xxxAutoConfiguration    this.deferredImportSelectorHandler.process();  }protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {       processConfigurationClass(new ConfigurationClass(metadata, beanName));  }protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {       // 根据当前类上面的@Conditional注解标注的条件判断是否要解析这个配置类     if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {          return;       }       // 以configClass作为key去获取,第一次来肯定是获取不到的,走下面逻辑     ConfigurationClass existingClass = this.configurationClasses.get(configClass);       if (existingClass != null) {           if (configClass.isImported()) {               if (existingClass.isImported()) {                   existingClass.mergeImportedBy(configClass);               }               // Otherwise ignore new imported config class; existing non-imported class overrides it.               return;           }           else {               // Explicit bean definition found, probably replacing an import.               // Let's remove the old one and go with the new one.  this.configurationClasses.remove(configClass);               this.knownSuperclasses.values().removeIf(configClass::equals);            }        }          // Recursively process the configuration class and its superclass hierarchy.      // 这一步其实没有做啥,重点还是看下一步骤      SourceClass sourceClass = asSourceClass(configClass);        do {      // 这里是重点,里面具体分为8大步骤,单独拿一小节分析    // b) doProcessConfigurationClass          sourceClass = doProcessConfigurationClass(configClass, sourceClass);        }        while (sourceClass != null);       // 放入configurationClasses中      this.configurationClasses.put(configClass, configClass);  }
// 上面的asSourceClass最终其实就是封装了一个SourceClass对象public SourceClass(Object source) {      this.source = source;      if (source instanceof Class) {          this.metadata = new StandardAnnotationMetadata((Class) source, true);      }      else {          this.metadata = ((MetadataReader) source).getAnnotationMetadata();      }  }

下面这个doProcessConfigurationClass具体分为8个小步骤去解析,对应步骤四种的A-H步骤

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)        throws IOException {      // 判断这个类上面有没有@Component注解     if (configClass.getMetadata().isAnnotated(Component.class.getName())) {          // Recursively process any member (nested) classes first    // 如果有的话,遍历其内部类,然后也是调用doProcessConfigurationClass递归处理        processMemberClasses(configClass, sourceClass);      }        // Process any @PropertySource annotations    // 处理PropertySource注解,之前讲解属性配置也分析过,就是将该注解对应的属性文件加载到Environment中    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(                                                 sourceClass.getMetadata(), PropertySources.class,                                                 org.springframework.context.annotation.PropertySource.class)) {          if (this.environment instanceof ConfigurableEnvironment) {              processPropertySource(propertySource);          }      }        // Process any @ComponentScan annotations     // 处理@ComponentScan注解,将其指定的包下的bean注册到框架中    Set componentScans = AnnotationConfigUtils.attributesForRepeatable(                                           sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);      if (!componentScans.isEmpty() &&             !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {          for (AnnotationAttributes componentScan : componentScans) {              // The config class is annotated with @ComponentScan -> perform the scan immediately              Set scannedBeanDefinitions =                           this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());              // Check the set of scanned definitions for any further config classes and parse recursively if needed              for (BeanDefinitionHolder holder : scannedBeanDefinitions) {                   BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();                   if (bdCand == null) {                       bdCand = holder.getBeanDefinition();                   }                   if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {                       parse(bdCand.getBeanClassName(), holder.getBeanName());                   }              }          }      }        // Process any @Import annotations      // 处理Import注解    processImports(configClass, sourceClass, getImports(sourceClass), true);        // Process any @ImportResource annotations      // 处理@ImportResource注解,可以通过它来指定xml文件,BeanFactory就会读取这个xml文件将bean注册进去    AnnotationAttributes importResource =                             AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);      if (importResource != null) {          String[] resources = importResource.getStringArray("locations");          Class readerClass = importResource.getClass("reader");          for (String resource : resources) {              String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);              configClass.addImportedResource(resolvedResource, readerClass);          }      }        // Process individual @Bean methods      // 处理我们的类中使用@Bean注解的方法,添加到configClass的beanMethod中    Set beanMethods = retrieveBeanMethodMetadata(sourceClass);      for (MethodMetadata methodMetadata : beanMethods) {          configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));      }        // Process default methods on interfaces      // 处理接口的默认方法,遍历这个类的接口,判断有没有使用@Bean注解的非抽象方法,添加到configClass的beanMethod中    processInterfaces(configClass, sourceClass);        // Process superclass, if any      // 递归处理父类,这边返回父类上层方法会递归处理    if (sourceClass.getMetadata().hasSuperClass()) {         // 判断父类不为null且不在knownSuperclasses中且不以Java开头       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;  }[object Object]
(1)处理内部类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {      // Recursively process any member (nested) classes first      processMemberClasses(configClass, sourceClass);  } // Register member (nested) classes that happen to be configuration classes themselves. private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {       Collection memberClasses = sourceClass.getMemberClasses();      // 判断是否有内部类,没有的话直接不处理     if (!memberClasses.isEmpty()) {           List candidates = new ArrayList<>(memberClasses.size());           for (SourceClass memberClass : memberClasses) {         // 判断是否是配置类,判断也很简单,之前分析过,判断类上面有没有@Configuration注解、@Import、@ImportResource       // @Component、@ComponentScan以及@Bean标注的方法             if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&                       !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {        // 加入到candidates中然后排个序                  candidates.add(memberClass);               }           }           OrderComparator.sort(candidates);           for (SourceClass candidate : candidates) {            // 防止A引入防止A引入B,B引入A             if (this.importStack.contains(configClass)) {                  this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));               }               else {                  this.importStack.push(configClass);                  try {          // 放入栈中并遍历处理这些配置类,也是递归处理,调用之前的doProcessConfigurationClass处理这个配置类                    processConfigurationClass(candidate.asConfigClass(configClass));                  }                  finally {                      this.importStack.pop();                  }               }           }      }  }
(2)处理@PropertySource注解
@SpringBootApplication  @PropertySource({"demo.properties"})  public class Springboot2Application {
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(                                                  sourceClass.getMetadata(), PropertySources.class,                                                  org.springframework.context.annotation.PropertySource.class)) {      if (this.environment instanceof ConfigurableEnvironment) {    // 这边就不进去看了,主要是读取@PropertySource注解指定的文件,将其封装成一个属性集放入到环境中        processPropertySource(propertySource);      }  }
(3)处理@ComponentScan注解
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(                                         sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);  if (!componentScans.isEmpty() &&            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {      for (AnnotationAttributes componentScan : componentScans) {          // The config class is annotated with @ComponentScan -> perform the scan immediately    // 下面先分析这个parse方法        Set scannedBeanDefinitions =                       this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());          // Check the set of scanned definitions for any further config classes and parse recursively if needed          for (BeanDefinitionHolder holder : scannedBeanDefinitions) {              BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();              if (bdCand == null) {                  bdCand = holder.getBeanDefinition();              }        // 如果是配置类,再递归处理            if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {                  parse(bdCand.getBeanClassName(), holder.getBeanName());              }          }      }  }
public Set parse(AnnotationAttributes componentScan, final String declaringClass) {      ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,                             componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);        Class generatorClass = componentScan.getClass("nameGenerator");      boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);     // 设置一个bean名字生成器,默认就是使用org.springframework.beans.factory.support.BeanNameGenerator    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :                                                                        BeanUtils.instantiateClass(generatorClass));        // 就是默认的    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");      if (scopedProxyMode != ScopedProxyMode.DEFAULT) {          scanner.setScopedProxyMode(scopedProxyMode);      }      else {          Class resolverClass = componentScan.getClass("scopeResolver");    // 理解是元数据解析器        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));      }        // 设置下扫描的资源模式,是**/*.class    scanner.setResourcePattern(componentScan.getString("resourcePattern"));        // 添加IncludeFilter和ExcludeFilter    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {          for (TypeFilter typeFilter : typeFiltersFor(filter)) {              scanner.addIncludeFilter(typeFilter);          }      }      for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {          for (TypeFilter typeFilter : typeFiltersFor(filter)) {              scanner.addExcludeFilter(typeFilter);          }      }      // 设置是否懒加载    boolean lazyInit = componentScan.getBoolean("lazyInit");      if (lazyInit) {          scanner.getBeanDefinitionDefaults().setLazyInit(true);      }        // 解析扫描的包路径加入到basePackages中    Set basePackages = new LinkedHashSet<>();      String[] basePackagesArray = componentScan.getStringArray("basePackages");      for (String pkg : basePackagesArray) {          String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),                                                   ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);          Collections.addAll(basePackages, tokenized);      }      for (Class clazz : componentScan.getClassArray("basePackageClasses")) {    // 解析basePackageClasses所在的包并加入到basePackages        basePackages.add(ClassUtils.getPackageName(clazz));      }       // 如果是空的,将声明该注解所在的类的包加入到basePackages    if (basePackages.isEmpty()) {    // 通常我们的主配置类是没有声明包扫描的路径的,所以这里会将主配置类所在的包加到这里面        basePackages.add(ClassUtils.getPackageName(declaringClass));      }        // 添加一个ExcludeFilter,跳过声明该注解的类    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {         @Override         protected boolean matchClassName(String className) {             return declaringClass.equals(className);         }      });      return scanner.doScan(StringUtils.toStringArray(basePackages));  }
protected Set doScan(String... basePackages) {       Assert.notEmpty(basePackages, "At least one base package must be specified");       Set beanDefinitions = new LinkedHashSet<>();       // 遍历所有的包路径     for (String basePackage : basePackages) {     // 获取该包下面所有符合条件的BeanDefinition,然后遍历处理,下面会分析         Set candidates = findCandidateComponents(basePackage);           for (BeanDefinition candidate : candidates) {               ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);               candidate.setScope(scopeMetadata.getScopeName());         // 通过beanNameGenerator生成beanName             String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);       // 这两个if判断逻辑比较简单,就是设置一些Lazy、DependsOn属性             if (candidate instanceof AbstractBeanDefinition) {                  postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);               }               if (candidate instanceof AnnotatedBeanDefinition) {                  AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);               }         // 这边是检查下有没有之前定义过这个BeanDefinition             if (checkCandidate(beanName, candidate)) {                  BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);                  definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,                                                       definitionHolder, this.registry);                  // 将该beanDefinition加入到集合中,并注册到容器中                beanDefinitions.add(definitionHolder);                  registerBeanDefinition(definitionHolder, this.registry);               }          }      }      return beanDefinitions;  }
private Set scanCandidateComponents(String basePackage) {       Set candidates = new LinkedHashSet<>();       try {           // 扫描指定包路径及其子包下面的class文件,将其封装成Resource对象   // classpath*:com/lwh/springboot/**/*.class   String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +                                            resolveBasePackage(basePackage) + '/' + this.resourcePattern;           Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);              for (Resource resource : resources) {               if (resource.isReadable()) {                  try {                      MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);                      if (isCandidateComponent(metadataReader)) {                           ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);                           sbd.setResource(resource);                           sbd.setSource(resource);                           if (isCandidateComponent(sbd)) {                               candidates.add(sbd);                           }                      }                  }              }           }    }    return candidates;  }
// 通过之前设置的几个filter进行过滤protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {      for (TypeFilter tf : this.excludeFilters) {          if (tf.match(metadataReader, getMetadataReaderFactory())) {              return false;          }      }      for (TypeFilter tf : this.includeFilters) {          if (tf.match(metadataReader, getMetadataReaderFactory())) {              return isConditionMatch(metadataReader);          }      }      return false;  }
(4)处理@Import注解
// Process any @Import annotations  // getImports方法就是去递归扫描configClass上面所有的注解,将@Import注解标注的值放入importCandidates中,见下图processImports(configClass, sourceClass, getImports(sourceClass), true);
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) {      // 依次遍历判断类型    // 其中有一个是这个类型,@Import(AutoConfigurationImportSelector.class)    // 这个就是自动配置原理,导入xxxAutoConfiguration这些类                if (candidate.isAssignable(ImportSelector.class)) {                      // Candidate class is an ImportSelector -> delegate to it to determine imports                      Class candidateClass = candidate.loadClass();          // 实例化并调用xxxAware的方法并注入相关属性                    ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);                      ParserStrategyUtils.invokeAwareMethods(                                              selector, this.environment, this.resourceLoader, this.registry);         // 它是DeferredImportSelector类型的                    if (selector instanceof DeferredImportSelector) {                    // deferredImportSelectors = new ArrayList<>()      // 这边会将两个参数封装下加入到deferredImportSelectors中,后面处理      // 加入到deferredImportSelectors中后,具体的处理是this.deferredImportSelectorHandler.process();                        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);                      }                      else {        // 不是的话获取@Import导入的类名数组                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());                          Collection importSourceClasses = asSourceClasses(importClassNames);       // 然后再递归处理                        processImports(configClass, currentSourceClass, importSourceClasses, false);                      }                  }      // @Import(AutoConfigurationPackages.Registrar.class),我们的主配置类上面的注解就是这个类型    // 这个是用于导入主配置类所在包及其子包下的BeanDefinition                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);           // 这边就是将这两个参数作为key,value放入了一个map中               // this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);                     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));                  }           }        }        finally {           this.importStack.pop();        }     }  }
(5)处理@ImportSource注解
// 这种就是Spring中常用的通过XML形式注入的方式@SpringBootApplication  @ImportResource("test.xml")  public class Springboot2Application {
// Process any @ImportResource annotations// 可以使用@ImportResource注解指定xml文件,导入BeanDefinitionAnnotationAttributes importResource =                  AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);  if (importResource != null) {       String[] resources = importResource.getStringArray("locations");       Class readerClass = importResource.getClass("reader");       for (String resource : resources) {     // 就是test.xml         String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);           configClass.addImportedResource(resolvedResource, readerClass);       }  }public void addImportedResource(String importedResource, Class readerClass) {       // 这边就是放入到了map中,这边是先统一存放起来,在步骤五的4)在真正进行导入BeanDefinition     this.importedResources.put(importedResource, readerClass);  }private final Map> importedResources = new LinkedHashMap<>();
(6)处理@Bean标注的方法
// Process individual @Bean methods  // 获取当前类中的Bean方法Set beanMethods = retrieveBeanMethodMetadata(sourceClass);  for (MethodMetadata methodMetadata : beanMethods) {       // 这边也是加入到set中,见下面代码,也是在步骤五的3)中进行处理     configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));  }private final Set beanMethods = new LinkedHashSet<>();
(7)处理默认方法
// 默认方法举例,主配置类实现这个接口就可以public interface ConfigurationInterface {    @Bean    default Pig pig(){        return new Pig();    }}
// Process default methods on interfaces   processInterfaces(configClass, sourceClass); // Register default methods on interfaces implemented by the configuration class. // 这边也是递归处理其父接口,判断父接口中默认方法是不是@Bean方法 private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {       for (SourceClass ifc : sourceClass.getInterfaces()) {           Set beanMethods = retrieveBeanMethodMetadata(ifc);           for (MethodMetadata methodMetadata : beanMethods) {               if (!methodMetadata.isAbstract()) {                   // 也是在步骤五的3)中进行处理                 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));               }           }           processInterfaces(configClass, ifc);       }  }
(8)递归处理父类
// 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();      }  }

讲到这边步骤四中的大部分方法已经分析完了,但是还有一个重要步骤没有分析,就是导入xxxAutoConfiguration这些自动配置类部分。下面分析:

// 在解析@Import注解时,我们的AutoConfigurationImportSelector就是DeferredImportSelector类型的,它的意思是延迟导// 入. 为啥要延迟导入? 因为AutoConfigurationImportSelector是给容器中导入一些默认的组件,如果容器中已经有这种类型// 的组件了,那么就不再导入. 因此,它是故意先等SpringBoot容器去解析那些用户自定义的Bean,最后发现没有才来导入这// 些默认的组件if (selector instanceof DeferredImportSelector) {     // deferredImportSelectors = new ArrayList<>()   // 这边会将两个参数封装下加入到deferredImportSelectors中,后面处理   // 加入到deferredImportSelectors中后,具体的处理是this.deferredImportSelectorHandler.process();   this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);  }
// 步骤四就是从这里开始分析的public void parse(Set configCandidates) {      // 删除部分代码,实际执行时这里的configCandidates就一个springBootApplication代表的主配置类    for (BeanDefinitionHolder holder : configCandidates) {        // 获取BeanDefinition        BeanDefinition bd = holder.getBeanDefinition();          // 我们的SpringBootApplication会走到这边,下面先分析这边        parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());     }        // 给容器中导入xxxAutoConfiguration,我们现在分析这边    this.deferredImportSelectorHandler.process();  }
// 上面方法会走到这里public void processGroupImports() {      for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {     // 下面先分析这个getImports方法         grouping.getImports().forEach(entry -> {               ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());               try {                   processImports(configurationClass, asSourceClass(configurationClass),                   asSourceClasses(entry.getImportClassName()), false);               }           });      }  }public Iterable getImports() {      // 这边的deferredImports是通过grouping.add(deferredImport)添加进去的    for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {          this.group.process(deferredImport.getConfigurationClass().getMetadata(),                                                                         deferredImport.getImportSelector());      }      return this.group.selectImports();  }public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {      // 下面先分析下这个getAutoConfigurationEntry方法     AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)                       .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);       // 加入到这个autoConfigurationEntries中     this.autoConfigurationEntries.add(autoConfigurationEntry);       for (String importClassName : autoConfigurationEntry.getConfigurations()) {     // 接着依次遍历放入到这个map中,Map entries = new LinkedHashMap<>()         this.entries.putIfAbsent(importClassName, annotationMetadata);       }  }
// 这边就到了AutoConfigurationImportSelector类的方法中protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,                                                             AnnotationMetadata annotationMetadata) {      // 判断是否支持自动配置    if (!isEnabled(annotationMetadata)) {          return EMPTY_ENTRY;      }      // 这个attributes属性就是上图中显示的,用来过滤自动配置类的    AnnotationAttributes attributes = getAttributes(annotationMetadata);      // 下面分析这个方法,这个就是加载容器中的自动配置类    List configurations = getCandidateConfigurations(annotationMetadata, attributes);      // 去除重复的,方法就是放入set再放入list中    configurations = removeDuplicates(configurations);      // 去除掉应该被排除的    Set exclusions = getExclusions(annotationMetadata, attributes);      checkExcludedClasses(configurations, exclusions);      configurations.removeAll(exclusions);       // 通过filter过滤,下面分析,过滤完发现只有22个了    configurations = filter(configurations, autoConfigurationMetadata);      // 发布一个事件,好像没有做啥关键的    fireAutoConfigurationImportEvents(configurations, exclusions);      // 将configurations封装成AutoConfigurationEntry返回    return new AutoConfigurationEntry(configurations, exclusions);  }protected boolean isEnabled(AnnotationMetadata metadata) {      if (getClass() == AutoConfigurationImportSelector.class) {    // 判断有没有配置这个属性,没有的话默认为true,  // String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";        return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);      }      return true;  }
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {     // getSpringFactoriesLoaderFactoryClass()返回EnableAutoConfiguration.class,那么这边就是获取容器中所有的字段配置类    List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),                                                                                  getBeanClassLoader());      return configurations;  }
protected List getAutoConfigurationImportFilters() {      return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);  }

4、步骤五解析

// 上面分析的是配置类解析的步骤四parser.parse(candidates);// 下面来看第五步,步骤四中解析得到的配置类会放在configurationClasses中Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);this.reader.loadBeanDefinitions(configClasses);
public void loadBeanDefinitions(Set configurationModel) {    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();    for (ConfigurationClass configClass : configurationModel) {  loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);    }}
private void loadBeanDefinitionsForConfigurationClass(  ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {     // 判断是否应该跳过     if (trackedConditionEvaluator.shouldSkip(configClass)) {  return;     }     // 向容器中注入这个配置类所代表的的BeanDefinition     if (configClass.isImported()) {  registerBeanDefinitionForImportedConfigurationClass(configClass);     }     // 遍历这个配置类的所有的Bean方法,注入这些@Bean标注的方法要引入的BeanDefinition     for (BeanMethod beanMethod : configClass.getBeanMethods()) {  loadBeanDefinitionsForBeanMethod(beanMethod);     }     // 处理该配置类上的@ImportResource指定的配置文件,就是Spring中常用的XML配置方式     // 这边会通过解析该XML文件给容器中注入BeanDefinition,SpringBoot中不推荐这种方式,具体就不往下分析了     loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());        // 处理步骤四中D解析@Import注解时获得的importBeanDefinitionRegistrars,调用其registerBeanDefinitions     // 方法给容器中注入BeanDefinition,这在前面讲解@Import方式时已经讲过了     loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}
private void loadBeanDefinitionsFromRegistrars(Map registrars) {     registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry));}

以上是"SpringBoot如何解析配置类以及集成第三方配置"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

配置 处理 注解 方法 容器 就是 分析 步骤 代码 递归 属性 文件 两个 方式 类型 封装 信息 接口 第三方 上图 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技公司 上海挚品互联网科技有限公司 互联网科技公司简介 中关村互联网 科技集团 厦门中拓互联网络科技有限公司 奇酷互联网科技 互联网金融科技创新 互联网公司会议桌创意科技软装饰 互联网科技产品 以后互联网后是啥科技 金融科技与互联网金融相同和不同 哈尔滨屹滨互联网科技有限公司 坤平互联网科技 青海科技产业互联网发展 西安小鹰速贷互联网科技有限公司 科技互联网的核心竞争力 雨阳互联网卡科技有限公司 广州千川互联网科技有限公司 下一代互联网重大应用科技园 10位科技互联网大佬 广州万易互联网科技有限公司 互联网属科技 博兴的互联网电子科技公司 智腾互联网科技有限公司 互联网科技公司实习生 四川慕妮娅互联网科技有限公司 徐州市互联网科技有限公司 工业互联网山东科技大学 南通创西澳互联网科技有限公司 广州有谷有贝互联网科技有限公司
0