温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-12-16 17:15:33 来源:亿速云 阅读:261 作者:小新 栏目:开发技术

小编给大家分享一下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方法中会进行配置类的解析
@SpringBootApplication
public 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注解
@Configuration
public @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);     } }

@Component
public 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解析配置类的具体过程。上图是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,它是BeanFactoryPostProcessor
if (!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、配置类解析流程概述

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

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

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {       List<beandefinitionholder> 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<beandefinitionholder> candidates = new LinkedHashSet<>(configCandidates);       // 已处理集合     Set<configurationclass> alreadyParsed = new HashSet<>(configCandidates.size());       // 循环处理直到candidates.isEmpty()     do {     // 这边开始解析,对应步骤4         parser.parse(candidates);           parser.validate();           // 取出第四步解析得到的一些configurationClasses集合         Set<configurationclass> 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<string> 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<beandefinitionholder> 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<annotationattributes> 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 -&gt; perform the scan immediately  
            Set<beandefinitionholder> 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<? extends BeanDefinitionReader> 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<methodmetadata> 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 -&gt; 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<SourceClass> memberClasses = sourceClass.getMemberClasses(); 
     // 判断是否有内部类,没有的话直接不处理
     if (!memberClasses.isEmpty()) {  
         List<SourceClass> 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<AnnotationAttributes> 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<BeanDefinitionHolder> 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<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {  
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,  
                           componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);  
  
    Class<? extends BeanNameGenerator> 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<? extends ScopeMetadataResolver> 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<String> 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<BeanDefinitionHolder> doScan(String... basePackages) {  
     Assert.notEmpty(basePackages, "At least one base package must be specified");  
     Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();  
     // 遍历所有的包路径
     for (String basePackage : basePackages) {  
   // 获取该包下面所有符合条件的BeanDefinition,然后遍历处理,下面会分析
         Set<BeanDefinition> 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<BeanDefinition> scanCandidateComponents(String basePackage) {  
     Set<BeanDefinition> 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<SourceClass> 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<SourceClass> 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文件,导入BeanDefinition
AnnotationAttributes importResource =  
                AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);  
if (importResource != null) {  
     String[] resources = importResource.getStringArray("locations");  
     Class<? extends BeanDefinitionReader> 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<? extends BeanDefinitionReader> readerClass) {  
     // 这边就是放入到了map中,这边是先统一存放起来,在步骤五的4)在真正进行导入BeanDefinition
     this.importedResources.put(importedResource, readerClass);  
}
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources = new LinkedHashMap<>();
(6)处理@Bean标注的方法
// Process individual @Bean methods  
// 获取当前类中的Bean方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);  
for (MethodMetadata methodMetadata : beanMethods) {  
     // 这边也是加入到set中,见下面代码,也是在步骤五的3)中进行处理
     configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));  
}
private final Set<BeanMethod> 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<MethodMetadata> 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<beandefinitionholder> 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<group.entry> 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<string, annotationmetadata> 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<string> configurations = getCandidateConfigurations(annotationMetadata, attributes);  
    // 去除重复的,方法就是放入set再放入list中
    configurations = removeDuplicates(configurations);  
    // 去除掉应该被排除的
    Set<string> 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<string> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { 
    // getSpringFactoriesLoaderFactoryClass()返回EnableAutoConfiguration.class,那么这边就是获取容器中所有的字段配置类
    List<string> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),  
                                                                                getBeanClassLoader());  
    return configurations;  
}
protected List<autoconfigurationimportfilter> getAutoConfigurationImportFilters() {  
    return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);  
}

4、步骤五解析

// 上面分析的是配置类解析的步骤四
parser.parse(candidates);
// 下面来看第五步,步骤四中解析得到的配置类会放在configurationClasses中
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
this.reader.loadBeanDefinitions(configClasses);
public void loadBeanDefinitions(Set<ConfigurationClass> 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<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
     registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry));
}

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

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI