从源码看Spring Boot 2.0.1
Spring Boot 命名配置很少,却可以做到和其他配置复杂的框架相同的功能工作,从源码来看是怎么做到的。
我这里使用的Spring Boot版本是 2.0.1.RELEASE
Spring Boot最重要的注解: @SpringBootApplication
打开它:

其中的几个注解:
@SpringBootConfiguration 标注这个类是一个配置类,类似Spring的@Configuration
@EnableAutoConfiguration 开启自动配置
@ComponentScan 开启组件扫描
打开@SpringBootConfiguration:

可以看作是springboot将spring的Configuration注解进行一个包装
@EnableAutoConfiguration

@AutoConfigurationPackage 自动扫描包的注解
@Import({AutoConfigurationImportSelector.class}) 引入组件
这个@AutoConfigurationPackage注解就是扫描跟主配置类同级目录以及子目录下的包,这也是什么Spring Boot其他的包必须在主配置类同级或者子目录以下的原因。
这里最关键的就是@Import注解向容器里导入了什么组件,导入的AutoConfigurationImportSelector.class,打开这个类,注意:在Spring Boot1.5版本中这里导入的类是:EnableAutoConfigurationImportSelector,而EnableAutoConfigurationImportSelector是继承自AutoConfigurationImportSelector的。

里面有一个 selectImports() 方法很重要。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
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 StringUtils.toStringArray(configurations);
}
}
getCandidateConfigurations() 方法
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;
}
SpringFactoryLoader去加载一些组件的名字,看加载那些组件的名字,继续点开loadFactoryNames方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
loadSpringFactories方法:
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()) {
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);
}
}
}
标黄部分将url转何曾properties,通过传入的键获取值,在将值切割成一个个字符串,转成Array存到result里。
META-INF/spring.factories:

找到其中的
# Auto Configure
可以看到:

上图里面这么多的xxxAutoConfiguration就是我们的这么久得出的结果,最终就是加载这么多的类的全路径,然后springboot内部就是实例化这些类并加载到容器里面,完成springboot应用启动时的自动配置。
通过断点我们可以看到:

总结一下流程:
Spring Boot启动 >
@SpringBootApplication >
@EnableAutoConfiguration >
@AutoConfigurationPackage + @Import({AutoConfigurationImportSelector.class}) >
public String[] selectImports() {List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);} >
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(); >
classLoader.getResources("META-INF/spring.factories") >
org/springframework/boot/spring-boot-autoconfigure/2.0.1.RELEASE/spring-boot-autoconfigure-2.0.1.RELEASE.jar!/META-INF/spring.factories >
spring.factories:各种xxxxAutoConfiguration的全类名
从源码看Spring Boot 2.0.1的更多相关文章
- 从源码看Spring Security之采坑笔记(Spring Boot篇)
一:唠嗑 鼓捣了两天的Spring Security,踩了不少坑.如果你在学Spring Security,恰好又是使用的Spring Boot,那么给我点个赞吧!这篇博客将会让你了解Spring S ...
- 源码解读 Spring Boot Profiles
前言 上文<一文掌握 Spring Boot Profiles> 是对 Spring Boot Profiles 的介绍和使用,因此本文将从源码角度探究 Spring Boot Profi ...
- 头秃了,二十三张图带你从源码了解Spring Boot 的启动流程~
持续原创输出,点击上方蓝字关注我 目录 前言 源码版本 从哪入手? 源码如何切分? 如何创建SpringApplication? 设置应用类型 设置初始化器(Initializer) 设置监听器(Li ...
- 从源码理解Spring原理,并用代码实现简易Spring框架
前言(本文为原创,转载请注明出处) 个人之前对于框架的学习,就停留在配置,使用阶段.说实话过段时间就会忘得荡然无存.也不知道框架的运行逻辑,就是知道添加个注解,就可以用了. 由于实习,时间比较多,也感 ...
- 手把手教你调试SpringBoot启动 IoC容器初始化源码,spring如何解决循环依赖
授人以鱼不如授人以渔,首先声明这篇文章并没有过多的总结和结论,主要内容是教大家如何一步一步自己手动debug调试源码,然后总结spring如何解决的循环依赖,最后,操作很简单,有手就行. 本次调试 是 ...
- Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...
- spring boot 2.0 源码分析(一)
在学习spring boot 2.0源码之前,我们先利用spring initializr快速地创建一个基本的简单的示例: 1.先从创建示例中的main函数开始读起: package com.exam ...
- spring boot 2.0 源码分析(五)
在上一篇文章中我们详细分析了spring boot是如何准备上下文环境的,今天我们来看一下run函数剩余的内容.还是先把run函数贴出来: /** * Run the Spring applicati ...
- spring boot 2.0 源码分析(二)
在上一章学习了spring boot 2.0启动的大概流程以后,今天我们来深挖一下SpringApplication实例变量的run函数. 先把这段run函数的代码贴出来: /** * Run the ...
随机推荐
- Python 入门基础20 --面向对象_继承、组合
今日内容 组合:自定义类的对象作为类的属性 继承:父类与子类.多继承 1.组合 将自定义类的对象作为类的属性 class Teacher: def __init__(self, name): self ...
- java读取视频文件时长
1.下载jar包:http://www.sauronsoftware.it/projects/jave/index.php 2.上代码 @RequestMapping(value = "am ...
- 【Linux】VMware虚拟机中如何配置静态IP
此处详解如何在VMware虚拟机中配置静态IP. 上图是一个草图,大致说明下VMware网络情况.网段指某个IP范围,例如一栋小区楼和另一栋小区楼就不是一个网段 如果你在A小区,你女朋友在B小区,你想 ...
- sublime3添加python编译系统
好记性不如烂笔头 为sublime3添加python编译系统,这里使用的anonconda2中的python.exe(即python2.7版本) 步骤: (1)打开sublime,打开“工具-> ...
- git获取内核源码的方法
[转]http://www.360doc.com/content/17/0410/16/23107068_644444795.shtml 1. 前言 本文主要讲述ubuntu下通过git下载linux ...
- jdk8系列三、jdk8之stream原理及流创建、排序、转换等处理
一.为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX ...
- sipML5聊天功能实现
一.环境说明:在阅读sipML5的API文档时,发现它具有聊天的功能,于是在sipML5的源码中进行设定,实现了注册之后可以英文聊天(中文聊天需要在FreeSWITCh中进行设定). 二.具体配置: ...
- Oracle11默认用户名和密码
安装Oracle时,若没有为下列用户重设密码,则其默认密码如下: 用户名 / 密码 登录身份 说明s ...
- WebMvcConfigurerAdapter已过时
Spring Boot2.0的版本(创建的时候自动选择的这个版本),然后编译器告诉我WebMvcConfigurerAdapter已过时了 @Deprecated public abstract cl ...
- InterruptedException 异常
当一个方法后面声明可能会抛出InterruptedException 异常时,说明该方法是可能会花一点时间,但是可以取消的方法. 抛InterruptedException的代表方法有: 1. jav ...