springboot启动时自动装配过程

在深入研究了多个资源后,你可能已经注意到大多数文章都倾向于展示注解代码,并指出AutoConfigurationImportSelector作为Spring Boot自动装配机制的核心组件。然而,一个常见的疑问是:这些方法并不会自动执行,那么它们是在Spring Boot启动过程中的哪一步被调用以触发自动装配的呢?本文将系统地介绍Spring Boot自动装配的原理,解答这个问题。

在Spring Boot应用程序启动过程中,自动装配发生在特定的关键点上,这与Spring框架的生命周期紧密相关。具体来说,自动装配是由AutoConfigurationImportSelector类的selectImports()方法实现的,但这个方法并非自行调用,而是由Spring容器在特定阶段调用。

1.springboot启动流程

springboot启动流程前面文章已经详细讲解,文章传送Spring Boot 启动过程深度解析,这里只是简单描述

  • 创建SpringApplication实例:当调用SpringApplication.run()时,实际上是在构造一个新的SpringApplication对象。在构造过程中,会推断应用类型(如Servlet或Reactive),并加载初始化器(initializers)和监听器(listeners)。这些通常是从META-INF/spring.factories文件中自动发现的
  • 运行run方法:一旦创建了SpringApplication实例,就会调用其run()方法。此方法负责整个启动过程的核心工作,包括环境准备、上下文创建、bean定义加载等。
  • 环境准备:run()方法首先设置一些系统属性,并获取监听器集合。然后,它会准备应用的环境(Environment),这涉及到解析命令行参数、配置属性源等。
  • 创建应用上下文:根据应用类型的不同(Servlet、Reactive等),会选择合适的ApplicationContext实现类来创建应用上下文。例如,对于传统的Servlet Web应用,将使用AnnotationConfigServletWebServerApplicationContext。
  • 刷新上下文:一旦上下文被创建出来,就会对其进行刷新操作,这一步骤包括但不限于注册所有单例bean、触发各种事件以及调用任何必要的后处理器(post-processors)
  • 执行Runners:最后,在上下文刷新完成后,如果有实现了ApplicationRunner或CommandLineRunner接口的bean存在,它们将会被依次执行,允许开发者在应用程序完全启动后执行额外的逻辑
  • 发布启动完成事件:整个启动过程接近尾声时,还会发布一个ApplicationStartedEvent,表示Spring Boot应用已经成功启动。

请注意上面的“刷新上下文”也就是run方法中的refresh方法。该方法是中执行了父类的invokeBeanFactoryPostProcessors(beanFactory)方法;该方法调用所有实现了 BeanFactoryPostProcessor 接口的 Bean 工厂处理器。这一步非常关键,因为 ConfigurationClassPostProcessor 就是在这里被调用的,它负责解析带有 @Configuration 注解的类,并且会触发 AutoConfigurationImportSelector 来进行自动装配。
具体执行堆栈
->容器(可能是ServletWebServerApplicationContext)#refresh
->AbstractApplicationContext#refresh
->AbstractApplicationContext#invokeBeanFactoryPostProcessors
->PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
->PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
接下来的调用过程是springboot自动装配的关键代码,我会根据调用堆栈进行全面解析。

2.源码解析

2.1 invokeBeanFactoryPostProcessors

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

这个方法的主要完成了BeanFactoryPostProcessor接口的实现类按照正确的顺序被调用。主要做了三件事。

  • 如果beanFactory是否是BeanDefinitionRegistry类型,则会调用实现了BeanDefinitionRegistryPostProcessor接口的处理器,判断是否实现了PriorityOrdered或Ordered接口来决定执行顺序。
  • 对于实现了PriorityOrdered接口的处理器,会被最先调用;接下来调用实现了Ordered接口的处理器;最后是没有实现这两个接口的处理器。这里主要是为了保证在Spring容器初始化阶段,bean定义可以按预期的方式被处理和修改。
  • 处理没有实现BeanDefinitionRegistryPostProcessor接口的普通BeanFactoryPostProcessor,并同样判断它们是否实现了PriorityOrdered或Ordered接口来决定执行顺序。
public static void invokeBeanFactoryPostProcessors(
		// 接收一个可配置的bean工厂实例
        // 和一个实现了BeanFactoryPostProcessor接口的列表
        ConfigurableListableBeanFactory beanFactory, 
        List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { 

    // 使用警告来提示开发者不要轻易重构这段代码,因为它处理了特定的顺序逻辑
    // WARNING: Although it may appear that the body of this method can be easily refactored to avoid the use of multiple loops and multiple lists,
    // the use of multiple lists and multiple passes over the names of processors is intentional. We must ensure that we honor the contracts for PriorityOrdered
    // and Ordered processors. Specifically, we must NOT cause processors to be instantiated (via getBean() invocations) or registered in the ApplicationContext
    // in the wrong order.
	// 创建一个集合用于跟踪已经处理过的bean名称
    Set<String> processedBeans = new HashSet<>(); /
	// 判断beanFactory是否是BeanDefinitionRegistry类型
    if (beanFactory instanceof BeanDefinitionRegistry registry) { 
   		 // 存储普通的BeanFactoryPostProcessor
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>(); 
        // 存储BeanDefinitionRegistryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); 
		// 遍历传入的BeanFactoryPostProcessor列表
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { 
       		 // 如果当前processor也是BeanDefinitionRegistryPostProcessor
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor registryProcessor) { 
           		 // 调用其postProcessBeanDefinitionRegistry方法
                registryProcessor.postProcessBeanDefinitionRegistry(registry); 
                // 添加到registryProcessors列表
                registryProcessors.add(registryProcessor); 
            } else {
            	// 	添加到regularPostProcessors列表
                regularPostProcessors.add(postProcessor); 
            }
        }
        //下面是源码中的注释
       	// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		// Separate between BeanDefinitionRegistryPostProcessors that implement
		// PriorityOrdered, Ordered, and the rest.
		// 存储当前要处理的BeanDefinitionRegistryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); 
        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
		// 1.获取所有实现了PriorityOrdered类型的BeanDefinitionRegistryPostProcessor bean名称,并用这些处理器的postProcessBeanDefinitionRegistry方法
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); 
        for (String ppName : postProcessorNames) { 
        	// 判断该bean实现了PriorityOrdered接口
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { 
            	// 将其实例添加到currentRegistryProcessors
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); 
                // 记录已处理的bean名称
                processedBeans.add(ppName); 
            }
        }
        // 对处理器进行排序
        sortPostProcessors(currentRegistryProcessors, beanFactory); 
        // 将当前处理器添加到总处理器列表
        registryProcessors.addAll(currentRegistryProcessors); 
        // 调用这些处理器的postProcessBeanDefinitionRegistry方法,这里面有个扩展点,很多开源框架都是在这里进行的类手动注册。这里面会在接下来的文章中详细讲解。
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); 
        // 清空当前处理器列表
        currentRegistryProcessors.clear(); 

        // 类似的逻辑重复三次,分别针对Ordered和普通(未实现PriorityOrdered或Ordered)的BeanDefinitionRegistryPostProcessor
        // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
        
		// 2.获取所有实现了Ordered类型的BeanDefinitionRegistryPostProcessor bean名称,并用这些处理器的postProcessBeanDefinitionRegistry方法
		//...代码不在解释,与上面1一样的逻辑
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
         
        // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
       // 3.获取所有还没有处理的BeanDefinitionRegistryPostProcessor bean名称(不包含在processedBeans),并用这些处理器的postProcessBeanDefinitionRegistry方法
		//...代码不在解释,与上面1一样的逻辑
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); 
    } else {
    	// 如果beanFactory不是BeanDefinitionRegistry类型,则直接调用postProcessors的postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); 
    }
    
	// 获取所有BeanFactoryPostProcessor类型的bean名称
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); 
	// 创建存储实现了PriorityOrdered接口的BeanFactoryPostProcessor集合
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); 
    // 创建存储实现了Ordered接口但未实现PriorityOrdered接口的bean名称集合
    List<String> orderedPostProcessorNames = new ArrayList<>(); 
     // 创建存储既未实现PriorityOrdered也未实现Ordered接口的bean名称集合
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    // 遍历所有BeanFactoryPostProcessor类型的bean名称
    for (String ppName : postProcessorNames) { 
   		 // 如果该bean名称已经被处理过,则跳过
        if (processedBeans.contains(ppName)) { 
            continue;
            // 如果该bean实现了PriorityOrdered接口
        } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { 
        	// 将实例添加到priorityOrderedPostProcessors列表
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); 
          //如果该bean实现了Ordered接口
        } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { 
        	// 将名称添加到orderedPostProcessorNames列表
            orderedPostProcessorNames.add(ppName); 
        } else {
        	// 将名称添加到nonOrderedPostProcessorNames列表
            nonOrderedPostProcessorNames.add(ppName); 
        }
    }
    // 按照优先级调用剩余的BeanFactoryPostProcessor
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
	// 清除缓存
    beanFactory.clearMetadataCache(); 
}

接下来的调用堆栈:
->PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors执行完后,会执行一下调用堆栈
->PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors 这里面循环调用BeanDefinitionRegistryPostProcessor
->ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 这个方法很简单,主要通过registry的唯一标识符(哈希码)是否已经处理过。如果处理过就不在执行,如果未被处理过,添加入注册表集合中,然后调用processConfigBeanDefinitions方法

2.2.processConfigBeanDefinitions

这段代码是Spring框架中非常核心的部分,负责解析并注册由用户定义的配置类,使得Spring容器能够基于这些配置类来管理应用程序上下文中的bean。

  • 源码解释
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    // 创建一个列表来保存配置类的候选Bean
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	// 获取所有已注册的bean名称
	String[] candidateNames = registry.getBeanDefinitionNames();
	for (String beanName : candidateNames) {
		// 获取bean名称对应的BeanDefinition对象
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		// 通过属性判断判断该BeanDefinition是否已经被标记为配置类
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			// 不是配置类,则检查它是否有资格成为配置类,并将其加入列表
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}
	// 没有找到任何@Configuration注解的类,则直接返回
	if (configCandidates.isEmpty()) {
		return;
	}

	// 对配置类按照@Order注解指定的顺序进行排序
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});
	// 检查是否有自定义的bean,并设置相应的生成器
	SingletonBeanRegistry singletonRegistry = null;
	if (registry instanceof SingletonBeanRegistry sbr) {
		singletonRegistry = sbr;
		if (!this.localBeanNameGeneratorSet) {
			BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}
	// 初始化环境变量,没有则设置则创建默认的StandardEnvironment实例
	if (this.environment == null) {
		this.environment = new StandardEnvironment();
	}

	// 使用ConfigurationClassParser实例,解析@Configuration类
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = CollectionUtils.newHashSet(configCandidates.size());
	do {
		// 处理配置类的启动步骤
		StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
		// 解析配置类,这里面会调用到自动装配的核心处理逻辑。具体见下面代码解析
		parser.parse(candidates);
		// 验证配置类
		parser.validate();

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

		// 根据解析模型创建bean定义
		if (this.reader == null) {
			this.reader = new ConfigurationClassBeanDefinitionReader(
					registry, this.sourceExtractor, this.resourceLoader, this.environment,
					this.importBeanNameGenerator, parser.getImportRegistry());
		}
		//这里面有一个很关键的点,很多开源框架都是使用这里的功能进行扩展。我们常用的直接将接口注册到bean容器中就是基于这里配合其他的扩展点进行bean注册的。详细可以见一下篇文章
		this.reader.loadBeanDefinitions(configClasses);
		alreadyParsed.addAll(configClasses);
		processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

		candidates.clear();
		// 如果有新的bean被注册,则重新检查它们是否也是配置类
		if (registry.getBeanDefinitionCount() > candidateNames.length) {
			String[] newCandidateNames = registry.getBeanDefinitionNames();
			Set<String> oldCandidateNames = Set.of(candidateNames);
			Set<String> alreadyParsedClasses = CollectionUtils.newHashSet(alreadyParsed.size());
			for (ConfigurationClass configurationClass : alreadyParsed) {
				alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
			}
			for (String candidateName : newCandidateNames) {
				if (!oldCandidateNames.contains(candidateName)) {
					BeanDefinition bd = registry.getBeanDefinition(candidateName);
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
						candidates.add(new BeanDefinitionHolder(bd, candidateName));
					}
				}
			}
			candidateNames = newCandidateNames;
		}
	}
	while (!candidates.isEmpty());

	// 将ImportRegistry注册为单例bean,以便支持ImportAware @Configuration类
	if (singletonRegistry != null && !singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
		singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
	}

	// 注册PropertySource
	this.propertySourceDescriptors = parser.getPropertySourceDescriptors();

	// 清理外部提供的MetadataReaderFactory中的缓存
	if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory cachingMetadataReaderFactory) {
		cachingMetadataReaderFactory.clearCache();
	}
}

接下来调用栈
->ConfigurationClassParser#parse(Set configCandidates) 这里面有两部分,第一步调用parse(AnnotatedBeanDefinition beanDef, String beanName)主要用于解析和处理配置类(configuration classes) 从2.3-2.6讲解内部逻辑,第二部分调用this.deferredImportSelectorHandler.process()用于处理延迟导入选择器(DeferredImportSelector)。在所有标准的配置类被处理完之后,根据些条件或配置动态地导入额外的配置类或组件。
->ConfigurationClassParser#parse(AnnotatedBeanDefinition beanDef, String beanName) 这里面循环遍历BeanDefinitionHolder,根据BeanDefinitionHolder的类型调用不同参数的parse方法。而parse方法通过new不同的对象,调用processConfigurationClass方法
->ConfigurationClassParser#processConfigurationClass方法

2.3.ConfigurationClassParser#processConfigurationClass

Spring框架中用于处理配置类(@Configuration注解标注的类)的核心逻辑。负责解析、合并和处理配置类及其超类层次结构。

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) {
    // 检查条件评估器是否应该跳过当前配置类,里面使用@Conditional动态控制配置类的加载,下面会详细解释
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }
    // 获取已存在的配置类
    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
        // 如果当前配置类是从其他地方导入的
        if (configClass.isImported()) {
            if (existingClass.isImported()) {
                // 合并被导入的配置类
                existingClass.mergeImportedBy(configClass);
            }
            // 如果现有类不是导入的,则忽略新导入的类
            return;
        } else if (configClass.isScanned()) {
            String beanName = configClass.getBeanName();
            // 如果存在同名bean,则移除旧的bean定义
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            // 扫描到的隐式bean不应覆盖显式的导入
            return;
        } else {
            // 显式的bean找到了,可能替换了一个导入
            // 移除旧的配置类,并使用新的配置类
            this.configurationClasses.remove(configClass);
            removeKnownSuperclass(configClass.getMetadata().getClassName(), false);
        }
    }

    // 递归处理配置类及其超类层次结构
    SourceClass sourceClass = null;
    try {
        // 将配置类转换为SourceClass对象
        sourceClass = asSourceClass(configClass, filter);
        do {
            // 处理配置类及其内部类、方法等
            sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
        } while (sourceClass != null); 
    } catch (IOException ex) {
        throw new BeanDefinitionStoreException(
                "I/O failure while processing configuration class [" + sourceClass + "]", ex);
    }
    // 将处理后的配置类放入configurationClasses集合中
    this.configurationClasses.put(configClass, configClass);
}

shouldSkip():当Spring容器解析自定义Config类时,会调用shouldSkip方法来评估CustomCondition是否匹配当前上下文环境。如果条件不匹配,则该配置类会被跳过,不会被加载到Spring容器中

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
    // 没有元数据或者元数据没有被@Conditional注解标注,不跳过
    if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
        return false;
    }

    // 没有指定配置阶段,尝试推断
    if (phase == null) {
        if (metadata instanceof AnnotationMetadata annotationMetadata &&
                ConfigurationClassUtils.isConfigurationCandidate(annotationMetadata)) {
            // 是配置类,使用PARSE_CONFIGURATION阶段
            return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
        }
        // 否则使用REGISTER_BEAN阶段
        return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
    }
    // 收集所有符合条件的Condition实例
    List<Condition> conditions = collectConditions(metadata);
    for (Condition condition : conditions) {
        ConfigurationPhase requiredPhase = null;
        //果条件实现了ConfigurationCondition接口,则获取其要求的配置阶段
        if (condition instanceof ConfigurationCondition configurationCondition) {
            requiredPhase = configurationCondition.getConfigurationPhase();
        }
        // 条件的配置阶段与当前阶段匹配,并且条件不匹配,则跳过该类
        if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
            return true;
        }
    }
    // 所有条件都匹配,则不跳过该类
    return false;
}

2.4. ConfigurationClassParser#doProcessConfigurationClass

doProcessConfigurationClass 方法是一个核心的 Spring 配置类处理方法,通过递归方式处理配置类及其相关元素(如成员类、组件扫描、导入资源、@Import 注解、@Bean 方法等),确保这些配置信息能够被正确解析并注册到 Spring 容器中
主要功能包含:

  • 处理成员类:如果配置类被@Component注解标注,则递归处理其成员类(嵌套类)。
  • 处理属性源:遍历所有@PropertySource注解,并将其注册到propertySourceRegistry中。如果没有配置环境实现ConfigurableEnvironment,则忽略这些注解。
  • 处理组件扫描:查找本地声明的@ComponentScan注解,如果没有找到,则查找其元注解(间接包含的组合注解)。如果找到@ComponentScan注解,则立即执行组件扫描,并检查扫描结果中的bean定义是否有进一步的配置类,并在需要时递归解析。
  • 处理导入:处理任何@Import注解,将导入的类或配置解析为配置类。
  • 处理资源导入:处理任何@ImportResource注解,解析并添加导入的资源文件。
  • 处理@Bean方法:获取并处理所有标记了@Bean注解的方法,并将其添加到配置类中。如果方法被kotlin.jvm.JvmStatic注解标注但不是静态方法,则跳过该方法。
  • 处理接口中的默认方法:处理接口中的默认方法,确保它们被正确解析和注册。
  • 处理超类:如果当前类有超类且超类不是Java内置类,则递归处理超类。
protected final SourceClass doProcessConfigurationClass(
        ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException {

    // 检查配置类是标记@Component注解,递归处理
    if (configClass.getMetadata().isAnnotated(Component.class.getName())) { 
		// 递归处理成员类
        processMemberClasses(configClass, sourceClass, filter);  
    }

    // // 获取所有@PropertySource注解属性 循环处理
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), org.springframework.context.annotation.PropertySource.class,
            PropertySources.class, true)) {  
        if (this.propertySourceRegistry != null) {
			// 注册属性源
            this.propertySourceRegistry.processPropertySource(propertySource);  
        } else {
            logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                    "]. Reason: Environment must implement ConfigurableEnvironment"); 
        }
    }

    //获取所有直接声明的@ComponentScan注解
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScan.class, ComponentScans.class,
            MergedAnnotation::isDirectlyPresent);  

    // 没有找到本地声明的@ComponentScan注解,查找间接包含的组合注解元注解
    if (componentScans.isEmpty()) {
		// 获取所有元注解中的@ComponentScan
        componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(),
                ComponentScan.class, ComponentScans.class, MergedAnnotation::isMetaPresent);  
    }

    if (!componentScans.isEmpty()) {
		// 收集注册bean的条件
        List<Condition> registerBeanConditions = collectRegisterBeanConditions(configClass);  
        if (!registerBeanConditions.isEmpty()) {
			// 抛出异常,如果存在注册bean条件
            throw new ApplicationContextException(
                    "Component scan for configuration class [%s] could not be used with conditions in REGISTER_BEAN phase: %s"
                            .formatted(configClass.getMetadata().getClassName(), registerBeanConditions));  
        }
        for (AnnotationAttributes componentScan : componentScans) {
            // 执行组件扫描,解析组件
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());  
            // 检查扫描到的bean集合中是否有配置类,并递归解析
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				// 获取原始bean定义
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();  
				// 如果没有原始bean定义,则使用当前bean定义
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();  
                }
				// 递归解析配置类
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    parse(bdCand.getBeanClassName(), holder.getBeanName());  
                }
            }
        }
    }

    // 处理@Import注解
    processImports(configClass, sourceClass, getImports(sourceClass), filter, true); 

    // // 获取@ImportResource注解属性斌处理@ImportResource注解
    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);  
        }
    }

    //  // 获取所有@Bean方法元数据并处理@Bean注释的方法
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); 
    for (MethodMetadata methodMetadata : beanMethods) {
		// 跳过标记了kotlin.jvm.JvmStatic但不是静态的方法
        if (methodMetadata.isAnnotated("kotlin.jvm.JvmStatic") && !methodMetadata.isStatic()) {
            continue; 
        }
		// 添加@Bean方法
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));  
    }

    // 处理接口中的默认方法
    processInterfaces(configClass, sourceClass);  

    // 检查是否存在超类 并处理超类
    if (sourceClass.getMetadata().hasSuperClass()) {  
		// 获取超类名称
        String superclass = sourceClass.getMetadata().getSuperClassName();  
		// 检查超类是否是Java内置类
        if (superclass != null && !superclass.startsWith("java")) {
			// 检查超类是否已存在
            boolean superclassKnown = this.knownSuperclasses.containsKey(superclass);  
			// 将超类添加到knownSuperclasses超类集合中
            this.knownSuperclasses.add(superclass, configClass); 
            if (!superclassKnown) {
                //返回超类的SourceClass对象以进行递归处理
                return sourceClass.getSuperClass();  
            }
        }
    }

    // 没有超类 -> 处理完成
    return null;  
}

2.5.ComponentScanAnnotationParser#parse(AnnotationAttributes…

解析 @ComponentScan 注解的配置,使用 ClassPathBeanDefinitionScanner 执行类路径扫描。parse法支持多种配置选项,执行自定义的 BeanNameGenerator、ScopedProxyMode、包含、排除过滤器、懒加载策略等。最终,返回一组符合条件的 BeanDefinitionHolder 对象,这些对象会被注册到 Spring 容器中,以便在应用程序上下文中使用

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {

    // 创建 ClassPathBeanDefinitionScanner
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
            componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    // 获取nameGenerator,这里可以获取自定义的BeanNameGenerator。大家如果仔细观察SpringBootApplication注解,发现里面有一个nameGenerator属性,这里就可以获取你自己配置的nameGenerator,用来自定义bean名称,比如在名称前统一加一个字符串啥的。
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
            BeanUtils.instantiateClass(generatorClass));

    // 获取 scopedProxy 属性
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
        scanner.setScopedProxyMode(scopedProxyMode);
    } else {
        // 没有指定 scopedProxy,获取 scopeResolver 属性并设置 ScopeMetadataResolver
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }

    // 设置resourcePattern 属性
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));

    // 处理 includeFilters
    for (AnnotationAttributes includeFilterAttributes : componentScan.getAnnotationArray("includeFilters")) {
        List<TypeFilter> typeFilters = TypeFilterUtils.createTypeFiltersFor(includeFilterAttributes, this.environment,
                this.resourceLoader, this.registry);
        for (TypeFilter typeFilter : typeFilters) {
            scanner.addIncludeFilter(typeFilter);  // 添加包含过滤器
        }
    }

    // 处理 excludeFilters 
    for (AnnotationAttributes excludeFilterAttributes : componentScan.getAnnotationArray("excludeFilters")) {
        List<TypeFilter> typeFilters = TypeFilterUtils.createTypeFiltersFor(excludeFilterAttributes, this.environment,
                this.resourceLoader, this.registry);
        for (TypeFilter typeFilter : typeFilters) {
            scanner.addExcludeFilter(typeFilter);  // 添加排除过滤器
        }
    }

    // 设置 lazyInit 属性
    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
        scanner.getBeanDefinitionDefaults().setLazyInit(true);  // 设置默认的懒加载策略
    }

    // 初始化 basePackages 集合
    Set<String> basePackages = new LinkedHashSet<>();
    
    // 获取并处理 basePackages 属性
    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);  // 将解析后的包名添加到集合中
    }

    // 处理 basePackageClasses 属性
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
        basePackages.add(ClassUtils.getPackageName(clazz));  // 将类所在的包名添加到集合中
    }

    // 如果没有指定任何基础包,则使用声明类的包名
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

    // 添加一个排除过滤器,排除掉声明类本身
    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return declaringClass.equals(className);  // 排除声明类本身
        }
    });

    // 执行扫描结果
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

2.6.ClassPathBeanDefinitionScanner#doScan

doScan 方法是 Spring 组件扫描方法,遍历指定的基础包,查找符合特定条件的组件(类),并对每个组件进行一系列处理,包括解析作用域、生成 bean 名称、处理注解等。最终,返回一组符合条件的 BeanDefinitionHolder 对象,并将这些对象注册到 Spring 容器中,在应用程序上下文中使用。

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    // 用于存储 BeanDefinitionHolder 对象
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    // 遍历基础包
    for (String basePackage : basePackages) {
        // 查找组件(类)
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        // 遍历组件
        for (BeanDefinition candidate : candidates) {
            // 解析作用域并设置作用域
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            // 生成 bean 名称
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            // AbstractBeanDefinition 类型,进行后处理
            if (candidate instanceof AbstractBeanDefinition abstractBeanDefinition) {
                postProcessBeanDefinition(abstractBeanDefinition, beanName);
            }
            // AnnotatedBeanDefinition 类型,处理常见的定义注解
            if (candidate instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations(annotatedBeanDefinition);
            }
            // 检查 bean 是否有效
            if (checkCandidate(beanName, candidate)) {
                // 创建 BeanDefinitionHolder 
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                // 执行作用域代理模式
                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                // 将 BeanDefinitionHolder 添加到集合中
                beanDefinitions.add(definitionHolder);
                // 注册 bean
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    // 返回 BeanDefinitionHolder 
    return beanDefinitions;
}

上述部分将完成了@ComponentScan注解范围内的类的扫描和自动装配 。接下来执行deferredImportSelectorHandler.process();这部分主要提供了通过Springboot SPI机制加载包。
调用堆栈:

  • ConfigurationClassParser#parse(Set configCandidates)
  • ->DeferredImportSelectorHandler#process() 这里主要是获取DeferredImportSelectorGroupingHandler 并调用processGroupImports方法,而DeferredImportSelectorGroupingHandler 类的主要作用是对 DeferredImportSelector 进行分组和处理,确保这些选择器能够在所有常规配置类解析完成之后,按照一定的顺序或条件进行导入操作 ,
  • ->DeferredImportSelectorHandler#processGroupImports()主要功能是处理分组的延迟导入选择器(DeferredImportSelector)。通过遍历每个分组中的导入条目,使用过滤器来筛选符合条件的类,并调用 processImports 方法执行导入逻辑
  • ->DeferredImportSelectorGrouping#getImports():处理导入选择器(DeferredImportSelector)的分组和选择逻辑。遍历所有延迟导入选择器,并将每个选择器的配置类元数据和导入选择器传递给一个 group 对象进行处理。
  • ->接下来详细讲AutoConfigurationImportSelector#process

2.7.AutoConfigurationImportSelector#process()

这个方法主要功能就是校验AutoConfigurationImportSelector ,并使用AutoConfigurationImportSelector自动装配,到这里,大家应该就有点清楚自动装的原理了吧

public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    // 判断传入的 deferredImportSelector 是 AutoConfigurationImportSelector 的实例
    Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, 
        () -> String.format("Only %s implementations are supported, got %s", 
            AutoConfigurationImportSelector.class.getSimpleName(), 
            deferredImportSelector.getClass().getName())
    );
    // 将 deferredImportSelector 转换为 AutoConfigurationImportSelector 类型
    AutoConfigurationImportSelector autoConfigurationImportSelector = (AutoConfigurationImportSelector)deferredImportSelector;
    // 获取 AutoConfigurationReplacements 对象,包含了部分自动配置类的替换信息
    AutoConfigurationReplacements autoConfigurationReplacements = autoConfigurationImportSelector.getAutoConfigurationReplacements();
    // 每次调用 process 方法时,autoConfigurationReplacements 必须相同
    Assert.state(this.autoConfigurationReplacements == null || this.autoConfigurationReplacements.equals(autoConfigurationReplacements), 
        "Auto-configuration replacements must be the same for each call to process"
    );
    // 设置当前的 autoConfigurationReplacements
    this.autoConfigurationReplacements = autoConfigurationReplacements;
    // 获取自动配置条目(AutoConfigurationEntry),包含了需要导入的配置类列表,这里就获取了SPI配置内容
    AutoConfigurationEntry autoConfigurationEntry = autoConfigurationImportSelector.getAutoConfigurationEntry(annotationMetadata);
    // 将获取到的自动配置条目添加到 autoConfigurationEntries 列表中
    this.autoConfigurationEntries.add(autoConfigurationEntry);
    // 遍历自动配置条目中的所有配置类名称,并将它们与对应的元数据存储到 entries 映射中
    for(String importClassName : autoConfigurationEntry.getConfigurations()) {
        this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
}	

2.7.AutoConfigurationImportSelector#getAutoConfigurationEntry

根据传入的注解元数据判断是否启用自动配置,处理候选配置类、排除类以及过滤后的配置类,生成自动配置对象(AutoConfigurationEntry)

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    // 检查是否启用了自动配置
    if (!this.isEnabled(annotationMetadata)) {
        // 如果未启用,则返回一个空的 AutoConfigurationEntry
        return EMPTY_ENTRY;
    } else {
        // 获取注解属性
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        // 获取配置类列表,这里面主要读取了自动装配的配置信息
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        // 去除重复的配置类
        configurations = this.<String>removeDuplicates(configurations);
        // 获取需要排除的类集合
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        // 检查排除的类是否有效
        this.checkExcludedClasses(configurations, exclusions);
        // 从配置类列表中移除排除的类
        configurations.removeAll(exclusions);
        // 使用配置类过滤器进一步过滤配置类
        configurations = this.getConfigurationClassFilter().filter(configurations);
        // 触发自动配置导入事件
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        // 返回新的 AutoConfigurationEntry 对象,包含过滤后的配置类和排除的类
        return new AutoConfigurationEntry(configurations, exclusions);
    }
}
  • AnnotationMetadata:提供对类的注解元数据的访问接口,例如注解名称、属性等。
  • AutoConfigurationEntry:封装了自动配置条目的对象,包含了需要导入的配置类列表和排除的类集合。
  • AnnotationAttributes:封装了注解的属性值,通常用于获取注解的具体配置。
  • getCandidateConfigurations:获取配置类列表,通常是从 spring.factories 文件中读取的配置类。3.0是从.imports配置文件中
  • removeDuplicates:去除配置类列表中的重复项。
  • getExclusions:获取需要排除的类集合,通常来自注解属性。
  • checkExcludedClasses:检查排除的类是否有效,防止无效的排除操作。
  • getConfigurationClassFilter:获取配置类过滤器,进一步过滤配置类。
  • fireAutoConfigurationImportEvents:触发自动配置导入事件,通知相关的监听器。

接下来调用了AutoConfigurationImportSelector#getCandidateConfigurations。这个方法主要
ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation, this.getBeanClassLoader())加载配置

2.8.ImportCandidates#load

通过解析 META-INF/spring/.imports 文件来获取候选的自动配置类

private static final String LOCATION = "META-INF/spring/%s.imports";
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
    Assert.notNull(annotation, "'annotation' must not be null");
    // 传入的 classLoader 为 null,则使用默认的类加载器
    ClassLoader classLoaderToUse = decideClassloader(classLoader);
    // 构建资源文件的位置,格式为 "META-INF/spring/<annotationClassName>.imports"
    String location = String.format(LOCATION, annotation.getName());
    // 查找类路径下所有该位置的 URL 资源
    Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
    // 创建一个列表用于存储配置类名称
    List<String> importCandidates = new ArrayList<>();
    // 遍历找到的所有 URL 资源
    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        // 读取每个 URL 资源中的配置类名称,并添加到列表中
        importCandidates.addAll(readCandidateConfigurations(url));
    }
    // 返回ImportCandidates 对象,包含所有的配置类名称
    return new ImportCandidates(importCandidates);
}

3.总结

通过源码解读springboot 的自动装配应该是分两步。
通过源码ConfigurationClassParser#parse(Set configCandidates)分析

  • 加载配置类(@Configuration 类)
    在 Spring Boot 启动过程中,通过解析@Import 和 @ComponentScan 注解,加载并解析 @Configuration 注解标注的配置类。这些配置类通常包含应用程序的核心配置信息,并且可以通过 @Bean 注解定义 Bean,这一步主要是使用ConfigurationClassPostProcessor 负责解析所有的 @Configuration 类,并将它们注册到 Spring 容器中。加载的配置类通常包含 @Bean 注解的方法,用于定义应用程序中的各个组件。
  • 通过 SPI 机制加载配置的类
    这一步通过AutoConfigurationImportSelector 通过 ImportCandidates。从从 META-INF/spring/ 目录下的 .imports 文件中加载自动配置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值