Spring Boot源码解析(一) - 自动装配机制

Spring Boot源码解析(一) - 自动装配原理

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

一、注解解析

  • @SpringApplication

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

@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
@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
@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定义,从而实现更复杂的配置。

图片转存失败,建议将图片保存下来直接上传

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

二、spring boot 自动装配原理分析

初始化SpringApplication
@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)注册
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

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

Spring SPI机制
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的形式进行本地缓存,后续触发自动装配时,从本地缓存中获取自动装配类集合

Spring Boot启动的核心逻辑
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()做了什么?

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)做了什么?

@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)做了什么?

	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源码分析

	//调用 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) {
			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 (!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. 配置类解析器进行解析

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

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

自动装配核心逻辑 - AutoConfigurationImportSelector

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 本地缓存中获取keyEnableAutoConfiuration对应的自动装配类集合
  3. 使用LinkedHashSet对自动装配类做去重操作
  4. 将自动配置类与spring-autoconfigure-metadata.properties进行条件匹配过滤出需要导入的自动装配类 (例如 @ConditionalOnClass)
  5. 返回自动装配类数组

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

三、小结

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值