SpringBoot 自动装配原理

2023-01-08 21:19:44

什么是自动装配

  • springboot 定义一套接口规范,这套规范规定:springboot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories 文件,将文件中配置的类型信息加载到 spring 容器,并执行类中定义的各种操作
  • 对于外部 jar 来说,只需要按照 springboot 定义的标准,就能将自己的功能装置进 springboot

自动装配的作用

  • 自动装配能够很大程度减少开发人员对 bean 的装配工作,只需要通过把对应的 bean 对象配置到对应工程下 META-INF/spring.factories,就能够装配到 spring 容器中

DeferredImportSelector 接口分析

  • springboot 的 AutoConfigurationImportSelector 类实现 DeferredImportSelector 接口,并且实现内部接口 Group,重写 Group 的 process() 和 selectImports() 方法
  • DeferredImportSelector 接口的 process() 和 selectImports() 方法,在 spring 调用bean定义注册后置处理器的时候会调用这个两个方法
  • process() 方法会获取 spring.factories 中用户定义的 bean 列表,selectImports() 方法获取将 process() 方法获取的 bean 对象列表包装成 Group 接口的内部类 Entry 对象
  • 在获取到 Entry 对象列表之后,将这些 bean 对象注册到容器中
  • 之后 spring 会对容器中的 bean 对象列表进行实例化和属性填充
/**
 * 继承 ImportSelector 接口
 */
public interface DeferredImportSelector extends ImportSelector {

	/**
	 * 返回 Group 接口实现类的 class
	 */
	@Nullable
	default Class<? extends Group> getImportGroup() {
		return null;
	}


	/**
	 * Group 接口,使用必须实现这个类
	 */
	interface Group {

		/**
		 * 上面分组完成后 spring 会调用该方法,循环 List 里的 DeferredImportSelector 类,并循环调用 process()
		 */
		void process(AnnotationMetadata metadata, DeferredImportSelector selector);

		/**
		 * 每个 Group 只执行一次,返回一个迭代器,spring 会使用迭代器的 forEach 方法进行迭代,想要导入 spring 容器的类要封装成 Entry 对象
		 */
		Iterable<Entry> selectImports();


		/**
		 * Entry 实体类,持有注解和需要导入的类名称
		 */
		class Entry {

			private final AnnotationMetadata metadata;

			private final String importClassName;

			public Entry(AnnotationMetadata metadata, String importClassName) {
				this.metadata = metadata;
				this.importClassName = importClassName;
			}

			public AnnotationMetadata getMetadata() {
				return this.metadata;
			}

			public String getImportClassName() {
				return this.importClassName;
			}

			@Override
			public boolean equals(@Nullable Object other) {
				if (this == other) {
					return true;
				}
				if (other == null || getClass() != other.getClass()) {
					return false;
				}
				Entry entry = (Entry) other;
				return (this.metadata.equals(entry.metadata) && this.importClassName.equals(entry.importClassName));
			}

			@Override
			public int hashCode() {
				return (this.metadata.hashCode() * 31 + this.importClassName.hashCode());
			}

			@Override
			public String toString() {
				return this.importClassName;
			}
		}
	}

}


自动装配实现原理

AutoConfigurationGroup 实现类分析

  • spring 在容器刷新的时候会调用这两个方法
  • 调用两个方法之后,用户定义的 bean 对象会被注入到 spring 容器中,之后会统一对bean对象进行实例化和属性填充
// 解析用户定义在 spring.factories 中的 bean 对象
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
	// 确定是 AutoConfigurationImportSelector 子类
	Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
			() -> String.format("Only %s implementations are supported, got %s",
					AutoConfigurationImportSelector.class.getSimpleName(),
					deferredImportSelector.getClass().getName()));
	// 从 "META-INF/spring.factories" 文件获取需要的自动配置类
	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
			.getAutoConfigurationEntry(annotationMetadata);
	// 将需要的类传入全局变量,以便 selectImports 方法使用
	this.autoConfigurationEntries.add(autoConfigurationEntry);
	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
		this.entries.putIfAbsent(importClassName, annotationMetadata);
	}
}

// 将获取出来的bean对象排序、过滤包装成 DeferredImportSelector.Group.Entry 对象
@Override
public Iterable<Entry> selectImports() {

	// 没有需要自动装配的类,返回空集合
	if (this.autoConfigurationEntries.isEmpty()) {
		return Collections.emptyList();
	}

	// 去除不需要的
	Set<String> allExclusions = this.autoConfigurationEntries.stream()
			.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
	Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
			.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
			.collect(Collectors.toCollection(LinkedHashSet::new));
	processedConfigurations.removeAll(allExclusions);

	// 排序,封装对象并返回集合
	return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
			.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
			.collect(Collectors.toList());
}

  • 获取 spring.factories 中的 bean 对象列表
// 获取 spring.factories 中的 bean 对象
protected AutoConfigurationEntry  getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		// 获取注解的属性的内容
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		// 获取候选 bean,获取 spring.factories 中定义的bean
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		// 去重
		configurations = removeDuplicates(configurations);						
		// 去除排除的类					
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);			
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

流程总结

  • springboot 自动装配的流程
  • spring 容器刷新对 DeferredImportSelector 的处理
  • 作者:tytler
  • 原文链接:https://blog.csdn.net/qq_41956014/article/details/127755479
    更新时间:2023-01-08 21:19:44