行业资讯

Spring Boot源码解析

Spring Boot自动装配是Spring Boot框架的一个关键特性,它的目标是让开发者能够快速构建Spring应用程序,减少繁琐的配置工作。

  • @SpringApplication

从启动类@SpringApplication注解入手,@SpringBootApplication是一个组合注解,它是Spring Boot框架中常用的一个主要注解之一。它结合了多个注解,简化了Spring Boot应用程序的配置。

java复制代码@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

@SpringBootApplication 包含以下三个核心注解:

  1. @SpringBootConfiguration:这是Spring Boot框架中的一个元注解,用于标识该类为Spring Boot的配置类。配置类是用来定义Bean和配置应用程序的类。
  2. @EnableAutoConfiguration:这个注解告诉Spring Boot根据类路径下的依赖和配置自动配置Spring应用程序。它利用了Spring Boot的自动配置特性,根据条件化配置的原理,自动配置所需的Bean、组件和属性。
  3. @ComponentScan:这个注解用于指定Spring Boot扫描组件的基础包。Spring Boot会扫描这个包及其子包,查找带有注解(例如@Controller、@Service、@Repository、@Component等)的类,并将它们注册为Spring管理的Bean。
java复制代码@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //标识为配置类
@EnableAutoConfiguration //开启自动配置
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ...省略
}

@EnableAutoConfiguration 是自动装配的核心,下面我们对该注解展开分析。

  • @EnableAutoConfiguration
java复制代码@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	...省略
}

在@EnableAutoConfiguration的源码中,可以看到它使用@Import注解引入了AutoConfigurationImportSelector类。当Spring bean后置处理器扫描解析启动类下所有包创建beanDefinition时,AutoConfigurationImportSelector会触发自动装配的加载过程。

  • @Import扩展点

@Import是一个用于导入其他配置类的扩展点。通过使用@Import注解,我们可以在一个配置类中引入其他的配置类,从而将它们的Bean定义和配置合并到当前配置中。

@Import导入配置类分为两种:

  • 实现ImportSelector接口的类,执行selectImports()返回一个字符串数组,其中包含要导入的配置类的全限定名。
  • 实现ImportBeanDefinitionRegistrar接口的类,执行registerBeanDefinition()可以动态地注册Bean定义,从而实现更复杂的配置。
Spring Boot源码解析(图1)

通过上述可知AutoConfigurationImportSelector 实现ImportSelector接口。该自动装配核心类逻辑在接下的分析中展开说

java复制代码@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        //第一步
        SpringApplication.run(MyApp.class, args);
    }
}


public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    	//第二步
		return new SpringApplication(primarySources).run(args);
	}

//第三步
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    	//资源加载器
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
    	//设置启动引导类
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    	//web应用类型:
    	// 1. NONE  非web应用程序
    	// 2. SERVLET web应用程序
    	// 3. REACTIVE 响应式web引用程序
    	//通过web应用类路径选择web应用类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    	//Spring SPI机制获取key为 ApplicationContextInitializer的类,并将它们作为应用程序上下文初始化器(ApplicationContextInitializer)注册
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    	//Spring SPI机制获取key为 ApplicationListener,并将它们作为应用程序事件监听器(ApplicationListener)注册

Spring Boot源码解析(图2)

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }

这块关注第一次调用Spring SPI机制的setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

java复制代码private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		//Spring SPI机制加载 META-INF/spring.factories 文件以key,value形式的自动装配类
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

通过 SpringFactoriesLoader.loadFactoryNames(type, classLoader) 方法,从 META-INF/spring.factories 文件中加载指定接口类型的实现类的名称集合,并将它们保存在一个 Set 中。

  • META-INF/spring.factories: 通常是用于自动装配的配置文件,其包含了需要自动装配的类的全限定名。

一些八股文认为在AutoConfigurationImportSelector使用Spring SPI加载META-INF/spring.factories获取自动装配类 ,其实不然,Spring SPI 只加载一次META-INF/spring.factories,以key-value的形式进行本地缓存,后续触发自动装配时,从本地缓存中获取自动装配类集合

java复制代码public ConfigurableApplicationContext run(String... args) {
   .
   .省略
   .
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //初始化并配置应用程序的环境,包括加载配置文件、解析命令行参数、设置系统属性等。
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
       //打印Banner
      Banner printedBanner = printBanner(environment);
      //根据web类型创建ApplicationContext
      context = createApplicationContext();
       //SpringBootExceptionReporter用于报告Spring Boot应用程序启动过程中的异常
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      //准备ApplicationContext,包括设置环境、配置监听器、初始化Bean等操作。
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      //这里会完成整个Spring IoC容器的初始化,包括解析Bean的定义,创建Bean实例,以及处理依赖注入等。
      refreshContext(context);
      .
      .省略
      .
   return context;
}

上述代码中,除了createApplicationContext()、refreshContext(context),其他部分与自动装配无关。在后续的文章中,会进一步介绍这部分内容。

createApplicationContext()做了什么?

java复制代码protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
                //根据webApplicationType枚举类型,创建应用
				switch (this.webApplicationType) {
				case SERVLET: //SERVLET web应用程序
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE: //REACTIVE 响应式web引用程序
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default: //NONE  非web应用程序
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

public AnnotationConfigServletWebServerApplicationContext() {
		//用于读取基于注解的Bean定义的类
		this.reader = new AnnotatedBeanDefinitionReader(this);
		//用于扫描类路径中的组件,并将其注册为Spring管理的Bean定义。
		this.scanner = new ClassPathBeanDefinitionScanner(this);
}

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
	//注册BeanFactory后置处理器
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}
	

//注册BeanFactory后置处理器
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
    	.
        .省略
        .
		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //自动装配重点:创建BeanFactory后置处理器 ConfigurationClassPostProcessor,用于扫描解析启动类当前包以及子包下的配置类
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
            //注册 ConfigurationClassPostProcessor
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		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));
		}

		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //创建BeanFactory后置处理器 CommonAnnotationBeanPostProcessor,处理依赖注入@Resource、WebServiceRef标注的字段以及方法
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
            //注册CommonAnnotationBeanPostProcessor
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
    	.
        .省略
        .

		return beanDefs;
	}

上述这段代码整体来说非常简单,根据 web应用类型创建ApplicationContext, 例如web应用类型为 SERVLET,创建AnnotationConfigServletWebServerApplicationContext。通过AnnotationConfigServletWebServerApplicationContext构造方法创建 AnnotatedBeanDefinitionReader以及ClassPathBeanDefinitionScanner,我们需要注意的是AnnotatedBeanDefinitionReader涉及BeanFactory后置处理器注册的内容,可以看到这一步注册了ConfigurationClassPostProcessor

  • AnnotatedBeanDefinitionReader: 用于读取基于注解的Bean定义的类
  • ClassPathBeanDefinitionScanner: 用于扫描类路径中的组件
  • ConfigurationClassPostProcessor : 用于扫描解析启动类当前包以及子包下的配置类

refreshContext(context)做了什么?

java复制代码@Override
	public void refresh() throws BeansException, IllegalStateException {
        ...省略
            
            /**
			 * 共注册了2个后置处理器
			 * ApplicationContextAwareProcessor,用于执行xxxAware接口中的方法
			 * ApplicationListenerDetector,保证监听器被添加到容器中
			 */
			prepareBeanFactory(beanFactory);
        try {
            
            //为容器的某些子类指定特殊的BeanPost事件处理器
            postProcessBeanFactory(beanFactory);

            //触发BeanFactory后置处理器
            //定位注册加载BeanDefinition, 能让我们对容器中扫描出来的BeanDefinition做出修改以达到扩展的目的
            invokeBeanFactoryPostProcessors(beanFactory);

            //说白了就是beanFactory.addBeanPostProcessor(postProcessor);添加bean后置处理器
            registerBeanPostProcessors(beanFactory);

            ////初始化容器事件传播器,添加事件传播器到IOC容器
            initApplicationEventMulticaster();

            //启动容器
            onRefresh();

            //为事件传播器注册事件监听器.
            registerListeners();

            //将解析的BeanDefinition注册到IOC容器中
            finishBeanFactoryInitialization(beanFactory);

            //初始化容器的生命周期事件处理器,并发布容器的生命周期事
            finishRefresh();
        }
        ...省略
    }

在refreshContext方法中,完成了整个Spring IoC容器的初始化,包括解析Bean的定义、创建Bean实例以及处理依赖注入等。我们主要关注invokeBeanFactoryPostProcessors(beanFactory)对配置类进行定位解析注册BeanDefinition

invokeBeanFactoryPostProcessors(beanFactory)做了什么?

java复制代码
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        //遍历内部所有BeanDefinitionRegistry后置处理器 (继承 BeanFactoryPostProcessor),
        //调用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 解析配置类成benaDefinition并注册
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

	//第二步: 

在invokeBeanFactoryPostProcessors方法中,会触发所有BeanFactory后置处理器的执行,其中ConfigurationClassPostProcessor后置处理器负责扫描解析启动类当前包以及子包下的配置类,并将其注册为Spring管理的BeanDefinition,接下来我们就看看它的源码

ConfigurationClassPostProcessor源码分析

java复制代码	//调用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 
        //获取传入的 BeanDefinitionRegistry 对象 registry 的哈希码,作为标识
		int registryId = System.identityHashCode(registry);
		//通过检查 registriesPostProcessed 集合和 factoriesPostProcessed 集合,防止了在同一个 BeanDefinitionRegistry 上重复执行逻辑
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + registry);
		}
		this.registriesPostProcessed.add(registryId);
        
        //第三步
		processConfigBeanDefinitions(registry);
	}
	
	//处理一些自定义的BeanDefinition
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

		//存放加了注解@Configuration @Component @ComponentScan @Import @ImportResource的类
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {

Spring Boot源码解析(图3)

BeanDefinition beanDef = registry.getBeanDefinition(beanName); //判断是否已经处理 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { //存放加了注解@Configuration @Component @ComponentScan @Import @ImportResource的类 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } ...省略 // 创建配置类解析器,构造方法会创建ComponentScanAnnotationParser扫描器 // 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()); do { //1.解析 parser.parse(candidates); //验证 parser.validate(); // 已经解析过的配置类 Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); // 移除已经解析过的配置类,防止重复加载了配置类中的bd configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } // 2. 将所有ConfigurationClass解析成BeanDefinition进行 @Condition... 匹配,然后注册到beanDefinition容器中 this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); candidates.clear(); // 如果大于,说明容器中新增了一些BeanDefinition,那么需要重新判断新增的bd是否是配置类,如果是配置类,需要再次解析 if (registry.getBeanDefinitionCount() > candidateNames.length) { String[] newCandidateNames = registry.getBeanDefinitionNames(); Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); Set<String> alreadyParsedClasses = new HashSet<>(); 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()); // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes // 注册ImportRegistry到容器中 // 当通过@Import注解导入一个全配置类A(被@Configuration注解修饰的类),A可以实现ImportAware接口 // 通过这个Aware可以感知到是哪个类导入的 if (sbr != null) { if (JNTY!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } } if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { // Clear cache in externally provided MetadataReaderFactory; this is a no-op // for a shared cache since it'll be cleared by the ApplicationContext. ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); } } //解析 public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<>(); // 在 new SpringApplication时候,会将 启动类 生成为AnnotatedBeanDefinition,然后注入到beanDefinition容器中 for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { //注解类解析方式 parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { //普通类解析方式 parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } //处理启动类的自动装配注解上@Import,对于 实现ImportSelector接口的执行selectImport processDeferredImportSelectors(); } private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; if (deferredImports == null) { return; } Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { // 获取启动类上的所有@Import的实现ImportSelector类,执行selectImports // 自动装配就在此处触发,获取类处境 String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); // 处理selectImports返回的可导入自动装配类 //1. 实现imporselect接口,则创建为实例调用selectImprot方法,然后递归调用处理import //2. 实现importRegistry接口,则缓存到importBeanDefinitionRegistrars集合 //3. 非上述接口,则当做配置类处理。解析@PropertySources、@ComponentScans、@Import、@Bean processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } } }

上述代码主要流程:

  1. 配置类解析器进行解析
  2. 注解方式解析 解析启动类@ComponentScans注解信息获取basePackages、basePackageClasses ,没有则将启动类包路径 创建ClassPathBeanDefinitionScanner 对当前包以及子包下所有后缀.class文件进行扫描解析 @Component、@Controller、@Service、@Repository 以及@Configura配置类的@PropertySources、@Import、@Bean生成ConfigurationClass 将ConfigurationClass与excludeFilters进行排除过滤、Conditional进行条件匹配
  3. 处理启动类上的@Import扩展点
  4. 将所有ConfigurationClass解析成BeanDefinition与 @ConditiOnXXX 进行条件匹配,最后注册到BeanDefinition容器中

@bean 等价于 factory-method
@bean 所在的类 等价于 factory-bean

自动装配核心逻辑 - AutoConfigurationImportSelector

java复制代码public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
        //加载组件自动配置类元信息spring-autoconfigure-metadata.properties 
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//获取key为EnableAutoConfiuration对应的value集合
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
		//自动装配类去重
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		//根据maven导入的启动器,过滤出需要导入的自动装配类
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return StringUtils.toStringArray(configurations);
	}

上面这段代码主要做了四件事

  1. 加载spring-autoconfigure-metadata.properties文件得到组件自动装配类元信息
  2. 从Spring SPI 本地缓存中获取key为EnableAutoConfiuration对应的自动装配类集合
  3. 使用LinkedHashSet对自动装配类做去重操作
  4. 将自动配置类与spring-autoconfigure-metadata.properties进行条件匹配过滤出需要导入的自动装配类 (例如 @ConditionalOnClass )
  5. 返回自动装配类数组

通过本文前部分的注解分析已知AutoConfigurationImportSelector实现ImportSelector接口。当ConfigurationClassPostProcessor后置处理器处理@Import时,就会触发自动装配核心类AutoConfigurationImportSelector#selectImprot() 获取Spring SPI 本地缓存key为EnableAutoConfiuration的自动装配类集合,然后去重过滤返回需要导入的自动装配类数组。

简单的来说,Spring Boot的自动装配原理主要依赖于Spring SPI机制+@Import扩展点+ ConfigurationClassPostProcessor实现。ConfigurationClassPostProcessor后置处理器会在扫描解析启动类当前包以及子包下的配置类,并将其注册为Spring管理的BeanDefinition,从而实现自动装配。而AutoConfigurationImportSelector作为自动装配核心类,在处理@Import逻辑中触发自动装配的过程,最终获取需要导入的自动装配类集合,实现Spring Boot的自动装配功能。


JNTY体育