SpringBoot如何实现自动装配

加载spring.factories

springBoot启动时,会创建SpringApplication。进入其构造方法

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

这里会调用org.springframework.boot.SpringApplication#getSpringFactoriesInstance

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

最终会进入

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	
		try {
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(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;
		}
	
	}

这个方法的逻辑为从classpath下面读取META-INF/spring.factories下的文件。可能有很多个
按照键值对的方式读取,最终放到cache中,key为类型,value为一个集合存储了配置文件里的内容
形式为在这里插入图片描述

后续如果需要获取某个类型,直接从缓存中根据类型获取就好了

	MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

创建配置类实例

spring.factories里存放了各种springBoot所需的接口
这里举例例如springBoot监听器

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

会从spring.factories中获取
调用org.springframework.boot.SpringApplication#getSpringFactoriesInstances方法

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

从cache中获取到这个类型的所有配置并且都创建实例,后会进行排序

	AnnotationAwareOrderComparator.sort(instances);

根据@Order注解和PriorityOrdered接口进行排序

private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
		boolean p1 = (o1 instanceof PriorityOrdered);
		boolean p2 = (o2 instanceof PriorityOrdered);
		if (p1 && !p2) {
			return -1;
		}
		else if (p2 && !p1) {
			return 1;
		}

		int i1 = getOrder(o1, sourceProvider);
		int i2 = getOrder(o2, sourceProvider);
		return Integer.compare(i1, i2);
	}

两个原则继承PriorityOrdered靠前,Order注解越小越靠前
如果没有order注解,那么会给默认一个人整数最大值,排名靠后
后续就可以使用这些实例进行在适当的时机调用

EnableAutoConfiguration

EnableAutoConfiguration是springBoot自动装配的核心,也是开发最经常使用到的
通常使用会这么配置
在这里插入图片描述

那么springBoot是如何加载他们的
@SpringBootApplication注解中上默认有@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	Class<?>[] exclude() default {};

	
	String[] excludeName() default {};

}

其中有@Import(AutoConfigurationImportSelector.class)
那么在扫描bean时也会把AutoConfigurationImportSelector扫描到并加载
那么看这个关键类

AutoConfigurationImportSelector

ImportSelector

先看其接口

public interface ImportSelector {

	String[] selectImports(AnnotationMetadata importingClassMetadata);

	default Predicate<String> getExclusionFilter() {
		return null;
	}

}

ImportSelector介绍
在@Configuration标注的Class上可以使用@Import引入其它的配置类,其实它还可以引入org.springframework.context.annotation.ImportSelector实现类。ImportSelector接口只定义了一个selectImports(),用于指定需要注册为bean的Class名称。当在@Configuration标注的Class上使用@Import引入了一个ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean。来看一个简单的示例,假设现在有一个接口HelloService,需要把所有它的实现类都定义为bean,而且它的实现类上是没有加Spring默认会扫描的注解的,比如@Component、@Service等。
例如

public class HelloImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {HelloServiceA.class.getName(), HelloServiceB.class.getName()};
    }

}

@Configuration
@Import(HelloImportSelector.class)
public class HelloConfiguration {

}

DeferredImportSelector

DeferredImportSelector是ImportSelector的一个扩展;
在一个配置类中
ImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理之前,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理(注意,这里只是对@Bean修饰的方法的处理,并不是立即调用@Bean修饰的方法,这个区别很重要!);

DeferredImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理完毕之后,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理;
DeferredImportSelector的实现类可以用Order注解,或者实现Ordered接口来对selectImports的执行顺序排序;
ImportSelector与DeferredImportSelector区别分析

DeferredImportSelector 的预处理

在org.springframework.context.annotation.ConfigurationClassParser#processImports方法中

	for (SourceClass candidate : importCandidates) {
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate<String> selectorFilter = selector.getExclusionFilter();
						if (selectorFilter != null) {
							exclusionFilter = exclusionFilter.or(selectorFilter);
						}
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
							processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
						}
					}

如果扫描到的bean是ImportSelector类型的。那么实例化这个selector
如果不是DeferredImportSelector
那么直接调用selector.selectImports方法 返回的类会被扫描为bean
如果是DeferredImportSelector
那么调用this.deferredImportSelectorHandler.handle方法

	// ConfigurationClassParser.DeferredImportSelectorHandler#handle
	// deferredImportSelectors  保存待处理的 Selector  
	private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
	// configClass 是持有该@Import 注解的 配置类, importSelector 是引入的 DeferredImportSelector 
	public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
			// 将 DeferredImportSelector  和其引入的配置类保存起来。
			DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
			// 如果deferredImportSelectors 为空,则重新注册
			if (this.deferredImportSelectors == null) {
				DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
				handler.register(holder);
				handler.processGroupImports();
			}
			else {
				// 将当前的 config 和 Selector 的持有者保存起来
				this.deferredImportSelectors.add(holder);
			}
		}

当在@Configguration注解中的一个配置类其他逻辑被处理完毕之后,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理全部处理完毕之后(parse方法结束)
才会调用process方法

DeferredImportSelector 的真正处理

在 ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>) 中最后一句处理了 DeferredImportSelector

	this.deferredImportSelectorHandler.process();

	public void process() {
		// 获取待处理的 DeferredImportSelectorHolder
		List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
		this.deferredImportSelectors = null;
		try {
			if (deferredImports != null) {
				DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
				// 排序
				deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
				// 1. 根据不同的group 进行分组注册
				deferredImports.forEach(handler::register);
				// 2. 按照分组调用
				handler.processGroupImports();
			}
		}
		finally {
			this.deferredImportSelectors = new ArrayList<>();
		}
	}

	DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
					deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
					deferredImports.forEach(handler::register);
					handler.processGroupImports();

如果有多个deferredImports,那么会排序并且分执行对应的register方法

handler::register

这里有两步操作 :

  1. 将不同的 DeferredImportSelectorHolder 按照分组进行划分
  2. 将DeferredImportSelectorHolder 的信息保存到 configurationClasses 中。(供后面调用的时候获取)
	public void register(DeferredImportSelectorHolder deferredImport) {
		// 获取当前 DeferredImportSelector  的Group
		Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
		DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
				(group != null ? group : deferredImport),
				key -> new DeferredImportSelectorGrouping(createGroup(group)));
		// 将当前 DeferredImportSelector  添加到同一分组中的
		grouping.add(deferredImport);
		// 保存需要处理的配置类
		this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getConfigurationClass());
	}

handler.processGroupImports()

这一步根据不同分组将分组中的 DeferredImportSelector 引入的类通过 entry.getImportClassName() 来包装后,调用 processImports 方法进行了新一轮解析。

	public void processGroupImports() {
		// 遍历每个分组
		for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
			// 获取分组的过滤器
			Predicate<String> exclusionFilter = grouping.getCandidateFilter();
			// 遍历分组中所有的 Entry (封装了需要引入的类的信息)
			grouping.getImports().forEach(entry -> {
				// 从 configurationClasses 集合中获取到对应的 ConfigurationClass 。其中保存
				ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
				try {
					// 对 configurationClass 进行解析。这里的解析在 ConfigurationClassPostProcessor  文章已经有过解释。
					// entry.getImportClassName() 获取到了引入的类
					processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
							Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
							exclusionFilter, false);
				}
				catch (BeanDefinitionStoreException ex) {
					throw ex;
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to process import candidates for configuration class [" +
									configurationClass.getMetadata().getClassName() + "]", ex);
				}
			});
		}
	}

其中 grouping.getImports() 的实现如下

	// org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#getImports
	public Iterable<Group.Entry> getImports() {
		for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
			// 调用 DeferredImportSelector.Group#process
			this.group.process(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getImportSelector());
		}
		// 调用 DeferredImportSelector.Group#selectImports
		return this.group.selectImports();
	}


我们这里调用的是 DefaultDeferredImportSelectorGroup

	private static class DefaultDeferredImportSelectorGroup implements Group {

		private final List<Entry> imports = new ArrayList<>();

		@Override
		public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
			// 调用了ImportSelector#selectImports 方法
			for (String importClassName : selector.selectImports(metadata)) {
				this.imports.add(new Entry(metadata, importClassName));
			}
		}

		@Override
		public Iterable<Entry> selectImports() {
			// 直接将 Imports 返回
			return this.imports;
		}
	}


综上可以看到 DeferredImportSelector 的处理过程并非是直接 调用ImportSelector#selectImports方法。而是调用 DeferredImportSelector.Group#process 和 Group#selectImports 方法来完成引入功能。

	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		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);
	}

从spring.factories中 配置为org.springframework.boot.autoconfigure.EnableAutoConfiguration排除需要排除掉的之后 都会被加载出来,注册成bean

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值