springboot自动配置原理分析
2021-01-24 17:06:47 65 举报
AI智能生成
springboot自动配置原理分析
作者其他创作
大纲/内容
结论:springboot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动装配类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功
1.springboot在启动的时候,从类路径下/META-INF/spring.factories获取@EnableAutoConfiguration指定的值;
2.将这些自动配置的类导入容器,自动配置就会生效,帮我们自动配置;
3.以前我们需要自动配置的东西,现在springboot帮我们做了;
4.整个javaEE,解决方案和自动配置的东西都在spring-boot-test-autoconfigure-2.4.2.jar这个包下;
5.它会把所有需要导入的组件,以全类名的方式返回,这些组件就会被添加到容器;
6.容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件,并自动配置,@Configuration,JavaCongfig;
7.有了自动配置类,免去了我们手动编写配置文件的工作。
@SpringBootApplication:标注这个类是一个springboot的应用:启动类下的所有资源被导入
@SpringBootConfiguration:springboot的配置
@Configuration :spring的配置类
@Component:说明这也是一个spring的组件
@EnableAutoConfiguration:自动配置
@AutoConfigurationPackage:自动配置包
@Import(AutoConfigurationPackages.Registrar.class):导入选择器‘包注册’
AutoConfigurationPackages:自动注册包,@ComponentScan扫描的包到AutoConfigurationPackages注册
Registrar:注册了源数据,导入了源数据,导入了包名(源数据metadata)
@Import(AutoConfigurationImportSelector.class):自动配置导入选择,自动导入包的核心
AutoConfigurationImportSelector:自动导入选择器,里面有环境、资源加载器等,选择了什么东西
selectImports():选择组件,加载源数据,选择pom.xml配置的东西
getAutoConfigurationEntry():获取自动配置的实体
//获取候选的配置
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//获取候选的配置,加载getSpringFactoriesLoaderFactoryClass()里面类的class
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
SpringFactoriesLoader.loadFactoryNames():获取所有的加载配置
getSpringFactoriesLoaderFactoryClass():标注了EnableAutoConfiguration注解的类,就可以获取这下面所有的配置,就是获取主启动类加载的所有组件
EnableAutoConfiguration.class:标注了这个类的所有包、所有配置
getBeanClassLoader()
beanClassLoader:当前类的加载器
Assert.notEmpty:断言、非空,如果配置不为空就会找META-INF/spring.factories
//标注了@EnableAutoConfiguration这个类的所有包所有配置
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
//获取当前类加载器
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }):扫描当前主启动类同级的包
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }):扫描当前主启动类同级的包
META-INF/spring.factories:自动配置的核心文件
SpringFactoriesLoader:spring工厂的加载
//获取所有的加载配置,加载了一个类,就是标注了@SpringBootApplication的这样一个类
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();//spring工厂的加载
}
String factoryTypeName = factoryType.getName();//获取类的名字
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());//获取默认的包名,断言不为空
}
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();//spring工厂的加载
}
String factoryTypeName = factoryType.getName();//获取类的名字
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());//获取默认的包名,断言不为空
}
loadSpringFactories():标注了@SpringBootApplication这样一个类,获取类的名字、获取默认的包名、断言不为空。首先会加载classload,这个classload标注了Application主启动类里面有@EnableAutoConfiguration;
//枚举去遍历一个url,url从类加载器中获取所有的资源,获取所有的系统资源,有一个while循环,这个url判断有没有更多的元素,如果有就把它放到url里面,然后把url加载到properties里面,最后所有的东西都放到配置类里面去了,所有的资源都加载到配置类中
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);//枚举去遍历一个url,url从类加载器中获取所有的资源
while (urls.hasMoreElements()) {//有一个while循环,这个url判断有没有更多的元素,如果有就把它放到url里面,然后把url加载到properties里面,最后所有的东西都放到配置类里面去了
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();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);//枚举去遍历一个url,url从类加载器中获取所有的资源
while (urls.hasMoreElements()) {//有一个while循环,这个url判断有没有更多的元素,如果有就把它放到url里面,然后把url加载到properties里面,最后所有的东西都放到配置类里面去了
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();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
//获取项目资源
classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories":加载了META-INF/spring.factories这个文件下的所有东西,从这里获取配置文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);//所有的资源都加载到配置类中
从这些资源中遍历了所有的nextElement(自动配置),遍历完成之后,封装为properties供我们使用:枚举去遍历一个url,url从类加载器中获取所有的资源,有一个while循环,这个url判断有没有更多的元素,如果有就把它放到url里面,然后把url加载到properties里面,最后所有的东西都放到配置类里面去了,所有的资源都加载到配置类中
spring-boot-autoconfigure-2.4.2.jar
META-INF
spring.factories:里面有很多配置,如果没有的就需要手动配置,所有的自动配置类都在这里了
# Initializers:初始化的
# Application Listeners:监听的
# Auto Configuration Import Listeners:自动配置导入监听器
# Auto Configuration Import Filters:自动配置导入过滤器
# Auto Configure:自动配置,所有的自动配置类都在这里了,如果没有的就需要手动配置
# Application Listeners:监听的
# Auto Configuration Import Listeners:自动配置导入监听器
# Auto Configuration Import Filters:自动配置导入过滤器
# Auto Configure:自动配置,所有的自动配置类都在这里了,如果没有的就需要手动配置
思考:这么多自动配置为什么有的没有生效,需要导入对应的star才能有作用?
@Configuration(proxyBeanMethods = false):Java配置类
@ConditionalOnXxx:核心注解,如果这里面的条件都满足,才会生效
收藏
收藏
0 条评论
下一页