0


《SpringBoot启动流程五》:你真的知道SpringBoot自动装配原理吗(两万字图文源码分析)

一、前言

我们前四篇博文,详细讨论了SpringBoot整个启动流程。博文如下:

1> 《SpringBoot启动流程一》:万字debug梳理SpringBoot如何加载并处理META-INF/spring.factories文件中的信息;
2> 《SpringBoot启动流程二》:七千字源码分析SpringApplication构造阶段;
3> 《SpringBoot启动流程三》:两万+字图文带你debug源码分析SpringApplication准备阶段(含配置文件加载时机、日志系统初始化时机);
4> 《SpringBoot启动流程四》:图文带你debug源码分析SpringApplication运行阶段和运行后阶段。

在启动流程中涉及SpringBoot的自动装配,虽然在之前我们聊过<SpringBoot自动装配机制原理>,但其中没有聊到

@EnableAutoConfiguration

@Import

注解是在何时被扫描的,本文就这一部分展开讨论。

注:Spring Boot版本:2.3.7.RELEASE。

二、入口

在Spring应用上下文准备阶段prepareContext()方法将应用的启动类加到Context中。

在Spring应用上下文启动阶段,会进入到refreshContext()方法,具体代码执行流程如下:
在这里插入图片描述

ServletWebServerApplicationContext

的类图:
在这里插入图片描述
ServletWebServerApplicationContext间接继承自

AbstractApplicationContext

,所以最终会进入到

AbstractApplicationContext#refresh()

方法。

走到

AbstractApplicationContext#refresh()

方法便意味着Spring应用上下文进入Spring生命周期,Spring Boot核心特性随之启动,比如:自动装配。

三、处理自动装配

1、处理自动装配的入口

在这里插入图片描述
最终进入到

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory,List<BeanFactoryPostProcessor>)

方法中,自动装配在其中实现;
在这里插入图片描述

invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory,List<BeanFactoryPostProcessor>)

方法中,传入接收到的入参beanFactory类型为

DefaultListableBeanFactory


在这里插入图片描述
再看DefaultListableBeanFactory的类图:
在这里插入图片描述
其实现了

BeanDefinitionRegistry

接口,所以会进入到if代码块:
在这里插入图片描述
在进入if代码块之后,会做两个操作:

1> 首先,遍历传入的三个BeanFactoryPostProcessor对其做分类;

分为常规后置处理器集合regularPostProcessors 和 注册处理器集合registryProcessors;
在这里插入图片描述
分类之后,regularPostProcessors有一个成员,registryProcessors中有两个成员。

finalclassPostProcessorRegistrationDelegate{publicstaticvoidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory,List<BeanFactoryPostProcessor> beanFactoryPostProcessors){....// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors =newArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.// 这里只有一个值:org.springframework.context.annotation.internalConfigurationAnnotationProcessorString[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,true,false);for(String ppName : postProcessorNames){// internalConfigurationAnnotationProcessor实现了PriorityOrdered接口if(beanFactory.isTypeMatch(ppName,PriorityOrdered.class)){// 将ConfigurationClassPostProcessor添加到currentRegistryProcessors中
                currentRegistryProcessors.add(beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);}}// 对currentRegistryProcessors做一个排序sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);// 走到这里registryProcessors中有三个对象了// todo 核心所在invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());....}}

在这里插入图片描述
接着从BeanFactory中获取到

BeanDefinitionRegistryPostProcessor

的实现类

ConfigurationClassPostProcessor

,并将其添加到registryProcessors中;此时registryProcessors中有三个成员:

  1. SharedMetadataReaderFactoryContextInitializer的静态内部类CachingMetadataReaderFactoryPostProcessor
  2. ConfigurationWarningsApplicationContextInitializer的静态内部类ConfigurationWarningsPostProcessor
  3. ConfigurationClassPostProcessor

2> 其次,执行当前注册处理器ConfigurationClassPostProcessor;

代码执行流程如下:
在这里插入图片描述
由于postProcessors中只有一个成员ConfigurationClassPostProcessor,进入到

ConfigurationClassPostProcessor

postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)

方法。
在这里插入图片描述

ConfigurationClassPostProcessor

processConfigBeanDefinitions(BeanDefinitionRegistry)

方法开始真正进入到处理自动装配的核心逻辑。

2、处理自动装配内容

1)找启动类,构建ConfigurationClassParser解析器准备解析启动类

首先从DefaultLisableBeanFactory中获取所有已经注册的BeanDefinition名称;
在这里插入图片描述
candidateNames中包含了我们的启动类,此外还有6个internalXxx类;然后遍历找到启动类,将其加到configCandidates集合中。
在这里插入图片描述
找到启动类(saintSpringBootApplicatioin)之后,构建一个配置类解析器ConfigurationClassParser,其中包括ComponentScanAnnotationParser、ConditionEvaluator,分别用于包扫描和条件装配;
在这里插入图片描述
接着调用ConfigurationClassParser#parse()方法开始解析启动类进行应用程序的启动。
在这里插入图片描述

2)解析启动类

以ConfigurationClassParser#parse()方法为入口,部分代码执行流程如下:
在这里插入图片描述
其中在做条件装配时,有个点需要注意一下:

ConfigurationCondition

接口内部的枚举类

ConfigurationPhase

中有两个值

PARSE_CONFIGURATION

REGISTER_BEAN

,分别表示:在类解析阶段做条件装配、在类注册阶段做条件装配。

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

在这里插入图片描述
1> 继续看获取SourceClass的代码逻辑:
在这里插入图片描述
其中会校验启动类上@SpringBootApplication注解的合法性,然后将启动类和其注解元数据AnnotationMetadata封装到SourceClass中返回。

如果获取不到SourceClass,则不会执行配置类(启动类)的处理。

2> 获取到SourceClass之后,处理配置类和SourceClass:
在这里插入图片描述

ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass,SourceClassPredicate<String>)

方法中会处理如下内容:

  1. 如果启动类configClass被@Component的衍生注解(递归注解的父注解可以找到@Component)标注,则首先递归处理所有成员(嵌套)类:即 configClass类内部如果找到成员类,会递归调用doProcessConfigurationClass()方法处理所有成员类。
  2. 解析启动类中所有的@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean注解。

具体代码如下:

classConfigurationClassParser{....@NullableprotectedfinalSourceClassdoProcessConfigurationClass(ConfigurationClass configClass,SourceClass sourceClass,Predicate<String> filter)throwsIOException{// 启动类configClass被@Component的衍生注解(递归注解的父注解可以找到@Component)标注if(configClass.getMetadata().isAnnotated(Component.class.getName())){// 首先递归处理所有成员(嵌套)类:configClass类内部如果找到成员类,会递归调用doProcessConfigurationClass()方法处理所有成员类。processMemberClasses(configClass, sourceClass, filter);}// Process any @PropertySource annotationsfor(AnnotationAttributes propertySource :AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(),PropertySources.class,org.springframework.context.annotation.PropertySource.class)){if(this.environment instanceofConfigurableEnvironment){processPropertySource(propertySource);}else{
                logger.info("Ignoring @PropertySource annotation on ["+ sourceClass.getMetadata().getClassName()+"]. Reason: Environment must implement ConfigurableEnvironment");}}// Process any @ComponentScan annotationsSet<AnnotationAttributes> componentScans =AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(),ComponentScans.class,ComponentScan.class);if(!componentScans.isEmpty()&&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),ConfigurationPhase.REGISTER_BEAN)){//  componentScan中包含11个成员,对应于@ComponentScan中11个属性for(AnnotationAttributes componentScan : componentScans){// 处理@ComponentScan 中的属性,返回所有派生的@Component注解标注的类,然后立即进行扫描// 此处会找到basePackages,其默认为启动类所在的目录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// TODO 实际业务中这里定义了多个派生@Component注解标注的类,这里就会循环多少次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// getImports()方法从启动类中获取所有的@Import注解的内容processImports(configClass, sourceClass,getImports(sourceClass), filter,true);// Process any @ImportResource annotationsAnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(),ImportResource.class);if(importResource !=null){String[] resources = importResource.getStringArray("locations");Class<?extendsBeanDefinitionReader> readerClass = importResource.getClass("reader");for(String resource : resources){String resolvedResource =this.environment.resolveRequiredPlaceholders(resource);
                configClass.addImportedResource(resolvedResource, readerClass);}}// Process individual @Bean methodsSet<MethodMetadata> beanMethods =retrieveBeanMethodMetadata(sourceClass);for(MethodMetadata methodMetadata : beanMethods){
            configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));}// Process default methods on interfacesprocessInterfaces(configClass, sourceClass);// Process superclass, if anyif(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 recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturnnull;}....}

就一个最简单、最干净的SpringBoot程序来看,其中没有@PropertySource、@ImportResource注解,平时工程中也很少使用。所以本文我们着重看@ComponentScan、@Import两个注解的处理流程(也就是我们自动装配的核心所在)。

3)解析启动类中的@ComponentScan注解

// Process any @ComponentScan annotationsSet<AnnotationAttributes> componentScans =AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(),ComponentScans.class,ComponentScan.class);if(!componentScans.isEmpty()&&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),ConfigurationPhase.REGISTER_BEAN)){//  componentScan中包含11个成员,对应于@ComponentScan中11个属性for(AnnotationAttributes componentScan : componentScans){// 处理@ComponentScan 中的属性,返回所有派生的@Component注解标注的类,然后立即进行扫描// 此处会找到basePackages,其默认为启动类所在的目录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// TODO 实际业务中这里定义了多个派生@Component注解标注的类,这里就会循环多少次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());}}}}

首先获取启动类@SpringBootApplication注解中的11个属性,然后调用

ComponentScanAnnotationParser#parse()

方法处理@SpringBootApplication注解中的注解 并 设置到类路径BeanDefinition扫描器

ClassPathBeanDefinitionScanner

的相应属性中。

classComponentScanAnnotationParser{....publicSet<BeanDefinitionHolder>parse(AnnotationAttributes componentScan,String declaringClass){ClassPathBeanDefinitionScanner scanner =newClassPathBeanDefinitionScanner(this.registry,
                componentScan.getBoolean("useDefaultFilters"),this.environment,this.resourceLoader);Class<?extendsBeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");boolean useInheritedGenerator =(BeanNameGenerator.class== generatorClass);
        scanner.setBeanNameGenerator(useInheritedGenerator ?this.beanNameGenerator :BeanUtils.instantiateClass(generatorClass));ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");if(scopedProxyMode !=ScopedProxyMode.DEFAULT){
            scanner.setScopedProxyMode(scopedProxyMode);}else{Class<?extendsScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
            scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));}

        scanner.setResourcePattern(componentScan.getString("resourcePattern"));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);}}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);}}boolean lazyInit = componentScan.getBoolean("lazyInit");if(lazyInit){
            scanner.getBeanDefinitionDefaults().setLazyInit(true);}Set<String> basePackages =newLinkedHashSet<>();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")){
            basePackages.add(ClassUtils.getPackageName(clazz));}// 默认会走到这里if(basePackages.isEmpty()){// 默认,basePackages为启动类所在的目录。eg:启动类为com.saint.SaintSpringBootApplication,basePackages为:com.saint
            basePackages.add(ClassUtils.getPackageName(declaringClass));}

        scanner.addExcludeFilter(newAbstractTypeHierarchyTraversingFilter(false,false){@OverrideprotectedbooleanmatchClassName(String className){return declaringClass.equals(className);}});return scanner.doScan(StringUtils.toStringArray(basePackages));}}
basePackages

属性为@ComponentScan注解的默认扫描包路径,如果没指定该属性,则会将启动类所在的包作为默认值 赋值

basePackages

属性上(以启动类SaintSpringBootApplication为例,其默认扫包路径为:com.saint)。
在这里插入图片描述
给ClassPathBeanDefinitionScanner制定完所有属性之后,会调用其

doScan(String...)

方法扫描

basePackages

目录下的所有标注了

@Component

衍生注解(比如:@Controller、@Service、@Repository)的类。
具体代码执行流程如下:
在这里插入图片描述
获取并注册完所有的@Component衍生类之后,在递归对这些类做解析。
在这里插入图片描述

4)解析启动类中的@Import注解

在此之前,我聊SpringBoot自动装配都是说,@EnableAutoConfiguration注解中通过@Import注解导入了AutoConfigurationImportSelector.class,@EnableAutoConfiguration注解中的@AutoConfigurationPackage中通过@Import注解导入了AutoConfigurationPackages.Registrar.class类,但我并不知道这里的@Import是在何时处理的!!这里我们就看一下针对@Import注解是怎么处理的。

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

这里分两步,首先通过

getImports()

方法获取启动类中的@Import注解,然后再通过processImports()方法处理所有的@Import注解。

1> getImports()方法获取启动类中所有的@Import注解:
在这里插入图片描述
具体递归流程如下:
在这里插入图片描述
最终获取的@import注解有两个:
在这里插入图片描述

2> processImports()方法处理获取到的启动类中所有的@Import注解:

先处理AutoConfigurationPackages.Registrar.class类,再处理AutoConfigurationImportSelector类;
在这里插入图片描述
对AutoConfigurationPackages.Registrar.class类的处理比较简单,利用反射将其实例化之后,添加到启动类的

importBeanDefinitionRegistrars

属性中。

在这里插入图片描述
由于AutoConfigurationImportSelector实现了DeferredImportSelector接口,所以会对AutoConfigurationImportSelector进行一个处理:将

AutoConfigurationImportSelector

封装为

DeferredImportSelectorHolder

对象,然后添加到

ConfigurationClassParser

类的

deferredImportSelectors

属性中(供后面处理@Import内容)。
在这里插入图片描述

5)处理所有的自动装配类

最后回到

ConfigurationClassParser#parse()

方法中:
在这里插入图片描述
代码执行流程如下:
在这里插入图片描述
最终进入到

AutoConfigurationImportSelector

getAutoConfigurationEntry(AnnotationMetadata)

方法,这里的代码逻辑相信大家嘎嘎眼熟,在SpringBoot自动装配机制原理一文中我们聊过。

AutoConfigurationImportSelector

getAutoConfigurationEntry(AnnotationMetadata)

方法源代码如下:

protectedAutoConfigurationEntrygetAutoConfigurationEntry(AnnotationMetadata annotationMetadata){if(!isEnabled(annotationMetadata)){return EMPTY_ENTRY;}// 1. 获取@EnableAutoConfiguration标注类的元信息AnnotationAttributes attributes =getAttributes(annotationMetadata);// 2. 返回自动装配类的候选类名集合List<String> configurations =getCandidateConfigurations(annotationMetadata, attributes);// 3. 移除重复对象,因为 自动装配组件存在重复定义的情况
    configurations =removeDuplicates(configurations);// 4. 自动装配组件的排除名单Set<String> exclusions =getExclusions(annotationMetadata, attributes);// 5.1. 检查自动装配Class排除集合的合法性checkExcludedClasses(configurations, exclusions);// 5.2 排除掉不需要自动装配的Class
    configurations.removeAll(exclusions);// 6. 进一步过滤
    configurations =getConfigurationClassFilter().filter(configurations);// 7. 触发自动装配的导入事件,事件包括候选的装配组件类名单和排除名单。fireAutoConfigurationImportEvents(configurations, exclusions);returnnewAutoConfigurationEntry(configurations, exclusions);}

其负责拿到所有自动配置的节点,大致分为六步;

  1. 第一步,在getCandidateConfigurations()方法中利用Spring Framework工厂机制的加载器SpringFactoriesLoader,通过SpringFactoriesLoader#loadFactoryNames(Class, ClassLoader)方法读取所有META-INF/spring.factories资源中@EnableAutoConfiguration所关联的自动装配Class集合。
  2. 第二步,利用Set不可重复性对自动装配Class集合进行去重,因为自动装配组件存在重复定义的情况;
  3. 第三步,读取当前配置类所标注的@EnableAutoConfiguration注解的属性exclude和excludeName,并与spring.autoconfigure.exclude配置属性的值 合并为自动装配class排除集合
  4. 第四步,校验自动装配Class排除集合的合法性、并排除掉自动装配Class排除集合中的所有Class(不需要自动装配的Class)。
  5. 第五步,再次过滤后候选自动装配Class集合中不符合条件装配的Class成员;
  6. 最后一步,触发自动装配的导入事件。

phase1> getCandidateConfigurations() --> 获取自动装配类:

代码执行流程如下:
在这里插入图片描述

getSpringFactoriesLoaderFactoryClass()

方法返回我们熟悉的

EnableAutoConfiguration

注解类;
在这里插入图片描述
紧接着,

SpringFactoriesLoader.loadFactoryNames(Class<?>, ClassLoader)

方法会获取所有META-INF/Spring.factories的配置文件,进而获取到所有的自动装配类;

loadFactoryNames()原理如下:

  1. 搜索指定ClassLoader下所有的META-INF/spring.fatories资源内容;
  2. 将搜索到的资源内容作为Properties文件读取,合并为一个Key为接口的全类名、Value为实现类全类名 列表的Map,作为方法的返回值;
  3. 最后从上一步返回的Map中查找并返回方法指定类型 对应的实现类全类名列表

loadFactoryNames()方法源码解释如下:

privatestaticMap<String,List<String>>loadSpringFactories(@NullableClassLoader classLoader){// 先从缓存中获取MultiValueMap<String,String> result = cache.get(classLoader);if(result !=null){return result;}try{Enumeration<URL> urls =(classLoader !=null?
                                 classLoader.getResources(FACTORIES_RESOURCE_LOCATION):ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        result =newLinkedMultiValueMap<>();while(urls.hasMoreElements()){/**
             * 查找所有我们依赖的jar包,并找到对应有META-INF/spring.factories⽂件,然后获取⽂件中的内容
             * 
             * 第一次循环:file:/.../org/springframework/spring-beans/5.2.12.RELEASE/spring-beans-5.2.12.RELEASE.jar!/META-INF/spring.factories
             * 第二次循环:file:/.../org/springframework/boot/spring-boot/2.3.7.RELEASE/spring-boot-2.3.7.RELEASE.jar!/META-INF/spring.factories
             * 第三次循环:file:/../org/springframework/boot/spring-boot-autoconfigure/2.3.7.RELEASE/spring-boot-autoconfigure-2.3.7.RELEASE.jar!/META-INF/spring.factories
             */URL url = urls.nextElement();// 获取资源UrlResource resource =newUrlResource(url);// 获取资源的内容Properties properties =PropertiesLoaderUtils.loadProperties(resource);for(Map.Entry<?,?> entry : properties.entrySet()){String factoryTypeName =((String) entry.getKey()).trim();for(String factoryImplementationName :StringUtils.commaDelimitedListToStringArray((String) entry.getValue())){
                    result.add(factoryTypeName, factoryImplementationName.trim());}}}
        cache.put(classLoader, result);return result;}catch(IOException ex){thrownewIllegalArgumentException("Unable to load factories from location ["+
                                           FACTORIES_RESOURCE_LOCATION +"]", ex);}}
  • 第一次扫描:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Orm39VX-1648878127869)(./picture/SpringBoot/SpringBoot自动装配3.png)]
  • 第二次扫描:在这里插入图片描述在这里插入图片描述
  • 第三次扫描:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L3P2kP2p-1648878127870)(./picture/SpringBoot/SpringBoot自动装配6.png)]

phase5> getConfigurationClassFilter().filter(configurations) --> 过滤候选自动装配Class集合中不符合条件装配的Class成员:

这里分两步:

第一步:获取所有的Filter在这里插入图片描述

首先通过

getConfigurationClassFilter()

方法从所有

META-INF/spring.factories

文件中获取所有的自动装配过滤器

AutoConfigurationImportFilter

的实现类(一共有三个),然后实例化

AutoConfigurationImportSelector

类的内部类

ConfigurationClassFilter

,并将获取多的所有

AutoConfigurationImportFilter

的实现类集合赋值到ConfigurationClassFilter的

filters

属性中(后面会用到它做条件装配)。
在这里插入图片描述

第二步:执行条件装配

然后对获取到的所有自动装配类(最干净、最简单的SpringBoot程序有127个)执行过滤操作(条件装配)后,还剩23个自动装配类。
在这里插入图片描述
关于此处为什么127个自动装配类经过

AutoConfigurationImportFilter

过滤后只剩23个了,且听下回分解《SpringBoot自动装配中的条件装配》。

后面就一路返回返回返回!!!!
在这里插入图片描述

标签: spring boot java 后端

本文转载自: https://blog.csdn.net/Saintmm/article/details/124792341
版权归原作者 秃秃爱健身 所有, 如有侵权,请联系我们删除。

“《SpringBoot启动流程五》:你真的知道SpringBoot自动装配原理吗(两万字图文源码分析)”的评论:

还没有评论