我是如何做到springboot自动配置原理解析
一前言
springboot 2.0.0版本分析,整体的自动配置流程如下:

具体配置参考官方文档:springboot-doc
二 @SpringBootApplication
核心注解@SpringBootConfiguration其实就是@Configuration注解,表示是个配置类;@EnableAutoConfiguration表示springboot的自动配置机制;@ComponentScan表示扫描允许注册额外的配置类;
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// 排除不会被应用的自动配置类,classes形式
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
Class<?>[] exclude() default {};
// 排除不会被应用的自动配置类,字符串数组形式
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {};
// 扫描基本包
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
// 扫描基本类
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
三 AutoConfigurationImportSelector
点击@EnableAutoConfiguration 注解进入,看见@Import({AutoConfigurationImportSelector.class})是导入AutoConfigurationImportSelector类;
AutoConfigurationImportSelector 类是自动配置的核心类,其主要进行配置的功能是配置factory.properties和 spring内嵌集成引入的配置;
3.1 具体依赖图如下:

3.2 成员
// 表示不引入配置
private static final String[] NO_IMPORTS = new String[0];
// 配置日志
private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
// 排除的自动配置
private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
// 声明 beanFactory
private ConfigurableListableBeanFactory beanFactory;
// 声明 environment (全局环境)
private Environment environment;
// 声明 beanClassLoader (bean的类加载器,加载spring-autoconfigure-metadata.properties中集成类)
private ClassLoader beanClassLoader;
// 声明 resourceLoader (资源加载器,加载spring的 factory.properties配置类)
private ResourceLoader resourceLoader;
3.3 selectImports
selectImports 这个方法的主要功能就是导入factory.properties和 spring-autoconfigure-metadata.properties中的配置类;
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
try {
// 1 加载元数据信息,本质就是加载bean,这里的bean是指我我们spring-autoconfigure-metadata.properties中集成类
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
// 2 AnnotationAttributes本质是个map
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 3 获得 spring.factories 中的配置类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 4 配置类复制用于排序不需要的配置类
configurations = this.removeDuplicates(configurations);
// 优先级排序
configurations = this.sort(configurations, autoConfigurationMetadata);
// 需移除配置类
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// 校验移除
this.checkExcludedClasses(configurations, exclusions);
// 执行移除配置类
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
} catch (IOException var6) {
throw new IllegalStateException(var6);
}
}
}
1 分析
AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
进入方法发现加载的元数据信息的路径是 META-INF/spring-autoconfigure-metadata.properties
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
}
在自动配置包底下找到spring-autoconfigure-metadata.properties

点进属性文件发现都spring自动配置类名的配置信息,部分如下:
#Thu Mar 01 04:46:13 UTC 2018
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration=
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration.Configuration=
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,org.springframework.data.cassandra.core.ReactiveCassandraTemplate,reactor.core.publisher.Flux
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration.ConditionalOnClass=org.apache.solr.client.solrj.SolrClient,org.springframework.data.solr.repository.SolrRepository
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration=
............................
我们随意点开其中的一个配置类,比如第一个HttpMessageConvertersAutoConfiguration,其中的class注解如下,可以发现其自动配置类都是通过注解配置;
// 表示配置类相当于xml中的 bean标签
@Configuration
// 判定是否存在HttpMessageConverter.class类,如果不存在则引入
@ConditionalOnClass({HttpMessageConverter.class})
// 在这三个配置类配置之后再进行配置
@AutoConfigureAfter({GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class})
// 导入配置类相当于xml中的 import标签
@Import({JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class})
public class HttpMessageConvertersAutoConfiguration {
3 分析
this.getCandidateConfigurations(annotationMetadata, attributes);方法的主要功能是获取候选配置;
进入getCandidateConfigurations方法发现里面的主要方法是loadFactoryNames;
// 获得factory配置信息类名
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
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 方法 主要是2部分;第一个是loadSpringFactories(classLoader),第二个是getOrDefault
// 加载factory类名
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 返回类名的list
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
第一部分:
loadSpringFactories本质就是使用spring的Resource资源调用获得 spring.factories 中的配置类;
// 加载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 {
// 获得 `spring.factories` 配置类的URL
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
// 将 `spring.factories` 每个配置类的key 和 val 存储进 map
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
result.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var9) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
}
}
}
classLoader.getResources("META-INF/spring.factories") ;中找到自动配置包中的配置如下图:

spring.factories装载配置类部分信息如下,没错这些配置都是sping启动需要的配置类信息,监听器,过滤器,自动配置的start配置类,以及启动的失败的错误分析还有模板引擎的支持,详细大家翻下配置包即可;
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
....................................
第二部分:
getOrDefault是个Map集合,map中有这个key时,就使用这个key值,如果没有就使用默认值defaultValue,返回也就是类名的list;

我是如何做到springboot自动配置原理解析的更多相关文章
- 这样讲 SpringBoot 自动配置原理,你应该能明白了吧
https://juejin.im/post/5ce5effb6fb9a07f0b039a14 前言 小伙伴们是否想起曾经被 SSM 整合支配的恐惧?相信很多小伙伴都是有过这样的经历的,一大堆配置问题 ...
- springboot自动配置原理以及手动实现配置类
springboot自动配置原理以及手动实现配置类 1.原理 spring有一个思想是"约定大于配置". 配置类自动配置可以帮助开发人员更加专注于业务逻辑开发,springboot ...
- SpringBoot实战之SpringBoot自动配置原理
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- 3. SpringBoot ——自动配置原理浅析
SpringBoot的功能之所以强大,离不开它的自动配置这一大特色.但估计很多人只是知其然而不知其所以然.下面本人对自动配置原理做一个分析: 在使用SpringBoot时我们通过引入不同的Starte ...
- SpringBoot自动装配原理解析
本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等 我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序: @SpringBoo ...
- SpringBoot自动配置原理学习
介绍 构建Springboot项目时我们会创建一个启动类 @SpringBootApplication public class DemoApplication { public static voi ...
- SpringBoot自动配置原理
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 回顾前面Spring的文章(以学习的顺序排好): S ...
- 浅谈springboot自动配置原理
前言 springboot自动配置关键在于@SpringBootApplication注解,启动类之所以作为项目启动的入口,也是因为该注解,下面浅谈下这个注解的作用和实现原理 @SpringBootA ...
- SpringBoot系列二:SpringBoot自动配置原理
主程序类的注解 @SpringBootApplication 注解,它其实是个组合注解,源码如下: @Target({ElementType.TYPE}) @Retention(RetentionPo ...
随机推荐
- tomcat access日志
每次看access log都会记不住pattern里的各个标识代表的什么意思,记录下,备忘! tomcat的access log是由实现了org.apache.catalina.AccessLog接口 ...
- H3C 配置NAPT
- springboot + redis + 注解 + 拦截器 实现接口幂等性校验
一.概念 幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次 比如: 订单接口, 不能多次创建订单 支付接口, 重复支付同一笔订单只能扣一次钱 支付宝回调接口, 可能会多 ...
- echarts实现多条可拖动节点的折现图
这篇博文主要是利用echarts实现两条以及多条可拖动节点的曲线,demo脱胎于官方demo,在官方demo的基础上添加了另一条曲线.因为之前写过一篇在vue中使用echarts实现可拖动节点的折线图 ...
- P1014 高精度减法
题目描述 给你两个很大的正整数A和B,你需要计算他们的差. 输入格式 输入一行包含两个正整数A和B,以一个空格分隔(A和B的位数都不超过 \(10^5\) ,但是B有可能比A大) 输出格式 输出一行包 ...
- C# 命令行如何静默调用 del 删除文件
如果在 C# 命令行调用 del 删除文件,很多时候会提示是否需要删除,本文告诉大家如何调用命令行的时候静默删除 在C# 命令行 调用 del 删除文件的时候,会提示是否删除,通过在命令行加上 \Q ...
- sci,ei,istp三大科技文献检索系统
印刷版(SCI) 双月刊 ,500种 联机版(SciSearch) 周更新 ,600种 光盘版(带文摘)(SCICDE) 月更新 ,500种(同印刷版) 网络版(SCIExpanded) 周更新 ,6 ...
- testng+ant+jenkins持续集成UI自动化
一.环境搭建 1. 安装testNG插件到eclipse. -) 选择菜单 Help /Software updates / Find and Install. -) 点击add button然后在l ...
- Linux 内核端点
USB 通讯的最基本形式是通过某些称为 端点 的. 一个 USB 端点只能在一个方向承载数 据, 或者从主机到设备(称为输出端点)或者从设备到主机(称为输入端点). 端点可看作一 个单向的管道. 一个 ...
- 【20.51%】【codeforces 610D】Vika and Segments
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...