深入理解Spring Boot 自动装配原理

在学习Spring Boot中,最核心的两个原理就是 约定优于配置,自动装配,其实约定也是用于自动装配的,今天我们来分析一下,Spring Boot的自动装配是这么个过程。

Spring Boot 是这么开启自动装配?

@EnableAutoConfiguration 注解开启自动装配功能,这个注解是在启动类@SpringBootApplication 注解里面,所以当run 启动项目时就自动开启了spring boot 的自动装配功能

@EnableAutoConfiguration 是这么做到自动装配的呢

@Enable注解在spring 的作用就是把相关组件的Bean 装配到 Ioc 容器中。如果基于JavaConfig 的形式来完成Bean的装配的话就必须要使用 @Configuration 和@Bean注解,而@Enable 本质上就是针对这两个注解的封装,并且这些注解里面还携带了一个 @Import注解,答案就在@Import注解的配置类,用来描述自动装配的实现类
深入理解Spring Boot 自动装配原理_第1张图片

@Import 注解的作用?

@Import注解的作用就是 Spring 会解析到 @Import导入到配置类,从而通过这个配置类的描述来完成Bean的装配

@AutoConfigurationPackage

在进入@EnableAutoConfiguration 注解中,我们可以看到 不仅有 @Import 还有 @AutoConfigurationPackage 这个注解的作用就是:把使用了该注解的类的所在的包及子包下所有的组件扫描到Spring Ioc容器中。

AutoConfigurationImportSelector 实现,这么去做到自动装配?

AutoConfigurationImportSelector 类实现了 ImportSelector,中的selectImports 抽象方法,并且返回一个数组,这个方法的实现就是Spring Boot自动装配的实现,这里会把需要自动装配的类配置好,放到到这个数组,然后进行批量装配。

分析 selectImports 中的实现?

深入理解Spring Boot 自动装配原理_第2张图片
当前Spring Boot 版本为2.3.10.BUILD-SNAPSHOT 在低版本中,这里面应该还有一段代码是用处理:
1.META-INF/spring-autocomfigure-metadataproperties中加载自动装配的条件元数据,只有满足条件的Bean才能进行自动装配,在当前版本中,我们并没有看到这段处理代码,

2.收集所有符合条件的配置类,完成自动装配

AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);

这段代码中重点就在于getAutoConfigurationEntry方法中,这里是收集自动装配到配置类。

getAutoConfigurationEntry 实现,这么去收集符合条件的配置类?

深入理解Spring Boot 自动装配原理_第3张图片

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

分析一下代码:

AnnotationAttributes attributes = getAttributes(annotationMetadata);

读取 EnableAutoConfiguration 注解中的属性信息等 (需要排除的配置类)

	protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
		String name = getAnnotationClass().getName();
		AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
		Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
				+ " annotated with " + ClassUtils.getShortName(name) + "?");
		return attributes;
	}

也就是定义的属性字段,这里主要就是为了做排除自动配置所做的
深入理解Spring Boot 自动装配原理_第4张图片

List configurations = getCandidateConfigurations(annotationMetadata, attributes);

这里是最重要的点,获取所有自动装配的配置类。

	protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

这里使用了 SpringFactoriesLoader 约定俗成的加载方式,也点类似java中的SPI,简单来说就是通过 classpath 读取 META-INF/spring.factories,这个文件就存储了我们需要自动装配的配置类,文件以key-value方法存储
深入理解Spring Boot 自动装配原理_第5张图片
文件中就以这种形式存在:
深入理解Spring Boot 自动装配原理_第6张图片
里面的格式就这样,条件装配,这样子我们就可以把他自动装配进去。其实这里我理解就是 Spring boot Starter 约定的一些文件,然后读取出来进行装配。

configurations = removeDuplicates(configurations);

去掉重复的配置类,里面的实现很简单,转换成 LinkedHashSet

protected final  List removeDuplicates(List list) {
		return new ArrayList<>(new LinkedHashSet<>(list));
	}

Set exclusions = getExclusions(annotationMetadata, attributes);

根据EnableAutoConfiguration注解中属性,获取不需要自动装配的类名单

	protected Set getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		Set excluded = new LinkedHashSet<>();
		excluded.addAll(asList(attributes, "exclude"));
		excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
		excluded.addAll(getExcludeAutoConfigurationsProperty());
		return excluded;
	}

exclude 不需要自动装配的类
excludeName 不需要自动装配类的名称
getExcludeAutoConfigurationsProperty 获取配置文件中不需要自动装配的类:
String ENABLED_OVERRIDE_PROPERTY = “spring.boot.enableautoconfiguration”;

configurations.removeAll(exclusions);

取代不需要装配的配置类

configurations = getConfigurationClassFilter().filter(configurations);

进行过滤操作,不需要装配的类

fireAutoConfigurationImportEvents(configurations, exclusions);

自动装配的导入事件,事件可能包括候选的配置名单,和排除的配置名单

return new AutoConfigurationEntry(configurations, exclusions);
返回需要自动装配的类。
至此Spring Boot 自动装配原理分析完毕。

Spring Boot 自动装配核心过程

  1. 通过@Import(AutoConfigurationImportSelector.class) 实现配置类的导入,可以多个类装配注入
  2. AutoConfigurationImportSelector 实现了 ImportSelector 接口中的selectImports 方法用于实现选择性批量配置类的装配
  3. 通过 SpringFactoriesLoader 约定俗成的加载方式,读取classpath 下的META-INF/spring.factories ,实现自动装配的配置类
  4. 通过条件筛选,把不符合条件的配置类移除,最终完成自动装配。

你可能感兴趣的:(Springboot,spring,boot)