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);
}
可以看到该方法中通过classLoader去FACTORIES_RESOURCE_LOCATION加载了一系列的URL
那么就去SpringBoot的自动配置相关的jar包中一探究竟
查看spring.factories
可以看到所谓的URL其实就是类的全限定类名
而这些配置被加载后将以Map<String, List
那么又回到loadFactoryNames方法
getOrDefault就是map中的get方法
在spring.factories中找到factoryTypeName对应的URL,也就是所有自动装配类的全限定类名
factoryTypeName就是factoryType的名字
这个factoryType是SpringFactoriesLoader.loadFactoryNames()的参数getSpringFactoriesLoaderFactoryClass()传入的
该方法的返回值是EnableAutoConfiguration这个类的Class对象
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
所以loadFactoryNames就是加载EnableAutoConfiguration对应的自动配置类的全限定类名
有了这些自动配置类的类路径,就可以完成自动装配
随便查看一个自动配置类
@EnableConfigurationProperties就是开启对RabbitProperties这个类进行自动配置,RabbitProperties中默认配置了一些参数,可以看到关于rabbitmq的一些配置已经有了默认值
至此自动装配源码的全流程已经完成
另外解析一下EnableAutoConfiguration上的@AutoConfigurationPackage
可以看到
该类又导入了Registrar
其中PackageImports这个对象中就包含了一系列的包
在这个PackageImports的构造方法中就完成了包路径的扫描
可以看到先是获取了AutoConfigurationPackage这个注解的元数据,其中就包括AutoConfigurationPackage注解修饰类的类路径
那么AutoConfigurationPackage修饰了什么类呢,其实上面就已经见到过了
AutoConfigurationPackage修饰了@EnableAutoConfiguration注解,而@EnableAutoConfiguration又修饰了@SpringBootApplication,也就是说其实修饰的就是SpringBoot启动类,通过获取SpringBoot启动类的路径可以找到同级下所有包以及子包中类。
这就是为什么SpringBoot启动类要放在所有包的最外层才能正常启动的原因