概述
注意看代码加的中的注解
1.启动类上因为加上了 @EnableEurekaServer这个注解 才可以实现自动装配
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class);
}
}
2.自动装配的核心方法 loadSpringFactories()
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 注意这点 loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) 方法
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 注意这点 loadSpringFactories方法
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
// 这点才是真正从文件中加载需要自动装配类的业务逻辑
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
// 省略
。。。。。。。。。。。。。。。
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
3.loadFactoryNames()方法
注意这个方法是进入从META-INF/spring.factories文件下加载需要自动装配类的核心方法,但是这个方法会被调用很多次,比如:
1> SpringApplication.run(EurekaApplication.class) 中进入loadFactoryNames
//1. 进入 SpringApplication的构造方法中
SpringApplication.run(EurekaApplication.class)
// 2. 注意getSpringFactoriesInstances()方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 。。。 省略
// 光这里就调用了 getSpringFactoriesInstances()方法两次 但注意这里传入的参数类型不同
// 下面会用到这点差异
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
//3.再次进入到 pringFactoriesLoader.loadFactoryNames(type, classLoader)方法
// 注意看loadFactoryNames方法每次传入一个type
//光上次在构造函数中就传过来两个不同的类型 ApplicationContextInitializer.class
// 分别是 1> ApplicationListener.class 2>
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
// 再次进入到 pringFactoriesLoader.loadFactoryNames(type, classLoader)方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// ....
return instances;
}
2>通过@SpringBootApplication注解进入loadFactoryNames方法
// 1.进入@SpringBootApplication 注解
@Target({ElementType.TYPE})
//..
@SpringBootConfiguration
@EnableAutoConfiguration
// ....
)
public @interface SpringBootApplication {
// ....
}
// 2. 进入到@EnableAutoConfiguration注解
// 在这个注解里看到了 熟悉的@Import注解
// 自动注入就是通过这个注解对配置了@Configure的自动装配类进行自动注入的
//...
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
//...
}
// 3. 进入 AutoConfigurationImportSelector类
// 直接看 核心方法 selectImports
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
//...
// 注意这个方法 getCandidateConfigurations(annotationMetadata, attributes);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
// 4.进入 getCandidateConfigurations方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 在这里看以看到 这里通过 this.getSpringFactoriesLoaderFactoryClass()获得类的类型 传入
// loadFactoryNames方法中
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
到这里就展示了两种进入loadFactoryNames方法的途径,接下来解析这个方法:
a.可以看到这行代码,每次根据传入到loadFactoryNames方法里的类的类型获得类的全限定类名
String factoryClassName = factoryClass.getName();
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
b.loadSpringFactories方法从META-INF/spring.factories加载需要装配的类
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
}
cache.put(classLoader, result);
return result;
// 看下面debug 结果 result得到39种类型
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
spring-boot-autoconfigure-2.1.4.RELEASE.jarMETA-INFspring.factories 下面只有6种类型,在其它包下的META-INFspring.factories一定还有对应的33种
点开 EnableAutoConfiguration可以发现, 这242个才是SpringBoot提供的所有自动装配的类文件
再根据这个方法,我们可以知道 先获得factoryClass的名字,也就是那39个类的名字,然后根据这个名字去获得下面对应的类文件,所以可知当我们需要EnableAutoConfiguration的类时,根据它的名字去result中直接加载,SpringBoot只在第一次调用LoadFactoryNames方法时去spring.factories文件下扫描到result中存储,下次再访问时就不会再扫描磁盘,而是根据类的名字获取下面所有的类了,看下面这个判断:
if (result != null) { return result; } else { try {
4.上面从META-INFspring.factories文件加载类的逻辑说清楚后,再看@import获得自动装配类的逻辑
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 根据 org.springframework.boot.autoconfigure.EnableAutoConfiguration 这个类的名字
// 获得下面SpringBoot提供的242个可以自动装配的类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 这里通过
// org.springframework.boot.autoconfigure.condition.OnBeanCondition,
// org.springframework.boot.autoconfigure.condition.OnClassCondition,
// org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
// 这三个类对这242个类进行过滤 也就是@Condition注解 filiter 里面是具体的逻辑
// 过滤后返回 通过@ImportSelector即可自动创建对象到IOC
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
最后
以上就是甜美棒棒糖为你收集整理的SpringBoot自动装配原理详细讲解(清楚 明白)的全部内容,希望文章能够帮你解决SpringBoot自动装配原理详细讲解(清楚 明白)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复