SpringBoot自动装配源码解析

SpringBoot自动装配源码解析

要想了解自动装配原理首先需要了解@SpringBootApplication这个注解

进入这个注解内部可以看到如下

自动装配的实现离不开@EnableAutoConfiguration这个注解

@SpringBootConfiguration说明该启动类是一个配置类

进入@EnableAutoConfiguration

这个注解中又导入了AutoConfigurationImportSelector

其中selectImports()又去调用了getAutoConfigurationEntry()

进入getAutoConfigurationEntry()可以看到,又去调用了getCandidateConfigurations()

进入getCandidateConfigurations()

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),      getBeanClassLoader());

这一段代码就是核心

查看loadFactoryNames方法

该方法调用了loadSpringFactories方法

以下是loadSpringFactories方法的源码

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		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;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}

可以看到该方法中通过classLoaderFACTORIES_RESOURCE_LOCATION加载了一系列的URL

那么就去SpringBoot的自动配置相关的jar包中一探究竟

查看spring.factories

可以看到所谓的URL其实就是类的全限定类名

而这些配置被加载后将以Map<String, List>的形式存储

那么又回到loadFactoryNames方法

getOrDefault就是map中的get方法

spring.factories中找到factoryTypeName对应的URL,也就是所有自动装配类的全限定类名

factoryTypeName就是factoryType的名字

这个factoryTypeSpringFactoriesLoader.loadFactoryNames()的参数getSpringFactoriesLoaderFactoryClass()传入的

该方法的返回值是EnableAutoConfiguration这个类的Class对象

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}

所以loadFactoryNames就是加载EnableAutoConfiguration对应的自动配置类的全限定类名

有了这些自动配置类的类路径,就可以完成自动装配

随便查看一个自动配置类

@EnableConfigurationProperties就是开启对RabbitProperties这个类进行自动配置,RabbitProperties中默认配置了一些参数,可以看到关于rabbitmq的一些配置已经有了默认值

至此自动装配源码的全流程已经完成

另外解析一下EnableAutoConfiguration上的@AutoConfigurationPackage

可以看到

该类又导入了Registrar

其中PackageImports这个对象中就包含了一系列的包

1623855082601

在这个PackageImports的构造方法中就完成了包路径的扫描

可以看到先是获取了AutoConfigurationPackage这个注解的元数据,其中就包括AutoConfigurationPackage注解修饰类的类路径

那么AutoConfigurationPackage修饰了什么类呢,其实上面就已经见到过了

AutoConfigurationPackage修饰了@EnableAutoConfiguration注解,而@EnableAutoConfiguration又修饰了@SpringBootApplication,也就是说其实修饰的就是SpringBoot启动类,通过获取SpringBoot启动类的路径可以找到同级下所有包以及子包中类。

这就是为什么SpringBoot启动类要放在所有包的最外层才能正常启动的原因

posted @ 2021-02-02 17:09  编程の小白  阅读(170)  评论(0编辑  收藏  举报