SpringBoot自动配置原理学习
介绍
构建Springboot项目时我们会创建一个启动类
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
1. 在之前使用Spring框架时,我们一般会创建web.xml和spring-context.xml等文件配置组件扫描、调度器、视图解析器等。
2. 而在SpringBoot中则简单了很多,这里就有自动配置发挥作用。如默认用的内嵌式容器是 Tomcat ,端口默认设置为 8080
正式进入流程解析
首先看@SpringBootApplication这个注解
@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) })
@ConfigurationPropertiesScan
public @interface SpringBootApplication { }
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {};
String[] excludeName() default {}; }
@EnableAutoConfiguration的作用是开启自动配置
核心是@EnableAutoConfiguration注解
这就是Spring Boot自动配置实现的核心入口,重头戏是@Import注解,这个注解导入了AutoConfigurationImportSelector类,利用AutoConfigurationImportSelector(自动配置导入选择器)将所有符合自动装配条件的bean注入到IOC容器中
查看AutoConfigurationImportSelector类代码,重头戏是selectImports方法
selectImports何时被执行
Springboot应用启动过程中使用ConfigurationClassParser分析配置类时,发现注解中存在@Import(ImportSelector)的情况。
就会创建一个相应的ImportSelector对象, 并调用其方法 public String[] selectImports(AnnotationMetadata annotationMetadata)
selectImports()方法流程
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { // 省略。。 @Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1 判断是否开启自动配置,为false直接返回空字符数组
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 2 loadMetadata()去加载Spring预先定义的自动配置的依赖信息,下面会具体说明
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader);
// 3 该方法返回的就是配置项信息,下面会具体说明
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
// 省略。。。
}
2. loadMetadata()去加载Spring预先定义的自动配置的依赖信息
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while (urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
}
return loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
path的地址是
protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
里面的自动配置文件(部分)
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration.AutoConfigureBefore=org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.ConditionalOnClass=javax.sql.DataSource,org.springframework.batch.core.launch.JobLauncher
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
2.1 根据path获取文件的URL对象
2.2 遍历URL节点,将spring-autoconfigure-metadata.properties中的依赖信息加载到properties对象中
2.3 调用loadMetadata()方法把properties存储到PropertiesAutoConfigurationMetadata类中
3. 在这里面会调用一个方法getAutoConfigurationEntry(),该方法返回的就是配置项信息,进入这个方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
// 3.1
3 if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 3.2
6 AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 3.3
7 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 3.4
8 configurations = removeDuplicates(configurations);
// 3.5
9 Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
// 3.6
fireAutoConfigurationImportEvents(configurations, exclusions);
// 3.7
return new AutoConfigurationEntry(configurations, exclusions);
}
3.1 判断是否开启自动配置
3.2 getAttributes()方法获取@SpringBootApplication(主要是为了获取@EnableAutoConfiguation)注解上的属性
3.3 加载META-INF/spring.factories文件, 这个文件配置了具有哪些自动配置类,文件内容如下 ,具体代码如下

getCandidateConfigurations方法如下
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;
}
3.3.1 getSpringFactoriesLoaderFactoryClass方法返回EnableAutoConfiguration.class
3.3.2 SpringFactoriesLoader.loadFactoryNames会加载META-INF/spring.factories中EnableAutoConfiguration的值中定义的jar包,并将其封装到一个List中返回
3.4 removeDuplicates() 用LinkedHashSet去重,在包装成ArrayList
3.5 getExclusions()、checkExcludedClasses()、removeAll()、filter() 过滤注解中要排除的自动配置
3.6 fireAutoConfigurationImportEvents() 将自动配置导入监听
3.7 返回配置的AutoConfigurationEntry包装类
自动配置原理(简化版)
通过 @EnableAutoConfiguration 核心注解初始化,并扫描 ClassPath 目录中自动配置类。根据项目中需要添加的默认配置,如springMVC,就按一定规则获取默认配置并自动初始化所需要的 Bean。
1. 核心是@EnableAutoConfiguration
2. 里面会通过@Import注解导入(AutoConfigurationImportSelector.class)类
3. 调用importSelect方法,进行自动配置
3.1 判断是否开启了自动配置
3.2 getAutoConfigurationEntry方法会使用
SpringFactoriesLoader.loadFactoryNames方法加载classpath中spring.factories文件中EnableAutoConfiguration的配置类
3.3 经过去重,排除后会把这些配置导入监听
重点关注
@EnableAutoConfiguration
@Import
AutoConfigurationImportSelector类
selectImports方法
SpringFactoriesLoader.loadFactoryNames() 核心方法读取 ClassPath 目录下面的 META-INF/spring.factories 文件。
spring.factories 文件中存放springBoot自动配置类, 如Servlet、jpa
【示例】(JDBC)的DataSourceAutoConfiguration配置
在spring.factories中org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguratio
作用是:SpringBoot 自动配置DataSource
// 表示这是一个配置类
@Configuration(proxyBeanMethods = false)
// 判断当前项目classpath有没有这两个类 DataSource EmbeddedDatabaseType
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
// 将配置文件中对应的值和 DataSourceProperties 绑定起来,并把DataSourceProperties的属性值放到ioc容器中
@EnableConfigurationProperties(DataSourceProperties.class)
// 导入数据源注册类、数据源初始化类
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
// 省略。。
}
查看DataSourceProperties属性,提供的这些属性,就可以获取到在application.yml中提供的值来设置数据源了
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean { private ClassLoader classLoader; /**
* Name of the datasource. Default to "testdb" when using an embedded database.
*/
private String name; /**
* Whether to generate a random datasource name.
*/
private boolean generateUniqueName; /**
* Fully qualified name of the connection pool implementation to use. By default, it
* is auto-detected from the classpath.
*/
private Class<? extends DataSource> type; /**
* Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
*/
private String driverClassName; /**
* JDBC URL of the database.
*/
private String url; /**
* Login username of the database.
*/
private String username; /**
* Login password of the database.
*/
private String password; /**
* JNDI location of the datasource. Class, url, username & password are ignored when
* set.
*/
private String jndiName; 。。。省略
}
总结
Spring Boot 内部提供了很多自动化配置的类, 配置类会更加classpath下是否又相关依赖类,来判断是否要配置字节,所以当我们在pom中引入了相关依赖,就可以自动配置了

====== 【多学一点,for Better】======
SpringBoot自动配置原理学习的更多相关文章
- 这样讲 SpringBoot 自动配置原理,你应该能明白了吧
https://juejin.im/post/5ce5effb6fb9a07f0b039a14 前言 小伙伴们是否想起曾经被 SSM 整合支配的恐惧?相信很多小伙伴都是有过这样的经历的,一大堆配置问题 ...
- springboot自动配置原理以及手动实现配置类
springboot自动配置原理以及手动实现配置类 1.原理 spring有一个思想是"约定大于配置". 配置类自动配置可以帮助开发人员更加专注于业务逻辑开发,springboot ...
- SpringBoot自动配置原理
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 回顾前面Spring的文章(以学习的顺序排好): S ...
- SpringBoot实战之SpringBoot自动配置原理
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- 3. SpringBoot ——自动配置原理浅析
SpringBoot的功能之所以强大,离不开它的自动配置这一大特色.但估计很多人只是知其然而不知其所以然.下面本人对自动配置原理做一个分析: 在使用SpringBoot时我们通过引入不同的Starte ...
- 浅谈springboot自动配置原理
前言 springboot自动配置关键在于@SpringBootApplication注解,启动类之所以作为项目启动的入口,也是因为该注解,下面浅谈下这个注解的作用和实现原理 @SpringBootA ...
- SpringBoot系列二:SpringBoot自动配置原理
主程序类的注解 @SpringBootApplication 注解,它其实是个组合注解,源码如下: @Target({ElementType.TYPE}) @Retention(RetentionPo ...
- springBoot 自动配置原理--自己新建一个 starter
上篇我们说到 springboot 和 SSM 框架的区别,今天我们就看看 springboot 到底为我们做了哪些事情,让我们开发变得如此简单. springboot 中起着重要作用的是 start ...
- springBoot 自动配置原理
在之前文章中说过,springBoot会根据jar包去添加许多的自动配置,本文就来说说为什么会自动配置,自动配置的原理时什么? springBoot在运行SpringApplication对象实例化时 ...
随机推荐
- B君的历史——复数乘法&&爆搜
题意 设 $r = \frac{-1+\sqrt7 i}{2}$,对任意整数 $x, y$ 都可以找到一个有限的整数集合 $S$,使得 $$x + y\sqrt7 i = \sum_{k \in S ...
- LeetCode 439. Ternary Expression Parser
原题链接在这里:https://leetcode.com/problems/ternary-expression-parser/description/ 题目: Given a string repr ...
- CentOS yum repo
CentOS yum repo 阿里云的 一个是Centos-6的 一个是Centos-7 # CentOS 5 wget -O /etc/yum.repos.d/CentOS-Base.rep ...
- vue 首页导航+左侧菜单
1. Mock.js 前后端分离开发开发过程当中,经常会遇到以下几个尴尬的场景: 1. 老大,接口文档还没输出,我的好多活干不下去啊! 2. 后端小哥,接口写好了没,我要测试啊! 前后端分离之后,前端 ...
- vue 自动px单位自动转换rem
vue 适配移动端 假设设计图是375 第一步 安装 lib-flexible npm i lib-flexible --save 第二步 安装 px2rem-loader npm install p ...
- USACO 奶牛抗议 Generic Cow Protests
USACO 奶牛抗议 Generic Cow Protests Description 约翰家的N头奶牛聚集在一起,排成一列,正在进行一项抗议活动.第i头奶牛的理智度 为Ai,Ai可能是负数.约翰希望 ...
- hdoj - 1342 Lotto
Problem Description In a Lotto I have ever played, one has to select 6 numbers from the set {1,2,... ...
- 作业:分布式文件系统HDFS 练习
这个作业的要求来自于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3292. 利用Shell命令与HDFS进行交互 1.目录操作 H ...
- 【大数据应用技术】作业九|安装关系型数据库MySQL 安装大数据处理框架Hadoop
本次作业的要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3161 1.安装MySql 按ctrl+alt+t打开终端窗口,安 ...
- SpringMVC(上)
一.SpringMVC简介 (1)springMVC概述 Spring MVC属于SpringFrameWork的后续产品,Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块. 使用 ...