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的更多相关文章

  1. 从源码看Spring Security之采坑笔记(Spring Boot篇)

    一:唠嗑 鼓捣了两天的Spring Security,踩了不少坑.如果你在学Spring Security,恰好又是使用的Spring Boot,那么给我点个赞吧!这篇博客将会让你了解Spring S ...

  2. 源码解读 Spring Boot Profiles

    前言 上文<一文掌握 Spring Boot Profiles> 是对 Spring Boot Profiles 的介绍和使用,因此本文将从源码角度探究 Spring Boot Profi ...

  3. 头秃了,二十三张图带你从源码了解Spring Boot 的启动流程~

    持续原创输出,点击上方蓝字关注我 目录 前言 源码版本 从哪入手? 源码如何切分? 如何创建SpringApplication? 设置应用类型 设置初始化器(Initializer) 设置监听器(Li ...

  4. 从源码理解Spring原理,并用代码实现简易Spring框架

    前言(本文为原创,转载请注明出处) 个人之前对于框架的学习,就停留在配置,使用阶段.说实话过段时间就会忘得荡然无存.也不知道框架的运行逻辑,就是知道添加个注解,就可以用了. 由于实习,时间比较多,也感 ...

  5. 手把手教你调试SpringBoot启动 IoC容器初始化源码,spring如何解决循环依赖

    授人以鱼不如授人以渔,首先声明这篇文章并没有过多的总结和结论,主要内容是教大家如何一步一步自己手动debug调试源码,然后总结spring如何解决的循环依赖,最后,操作很简单,有手就行. 本次调试 是 ...

  6. Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...

  7. spring boot 2.0 源码分析(一)

    在学习spring boot 2.0源码之前,我们先利用spring initializr快速地创建一个基本的简单的示例: 1.先从创建示例中的main函数开始读起: package com.exam ...

  8. spring boot 2.0 源码分析(五)

    在上一篇文章中我们详细分析了spring boot是如何准备上下文环境的,今天我们来看一下run函数剩余的内容.还是先把run函数贴出来: /** * Run the Spring applicati ...

  9. spring boot 2.0 源码分析(二)

    在上一章学习了spring boot 2.0启动的大概流程以后,今天我们来深挖一下SpringApplication实例变量的run函数. 先把这段run函数的代码贴出来: /** * Run the ...

随机推荐

  1. C# 进程的挂起与恢复

    1. 源起: 仍然是模块化编程所引发的需求.产品经理难伺候,女产品经理更甚之~:p 纯属戏谑,技术方案与产品经理无关,芋头莫怪! VCU10项目重构,要求各功能模块以独立进程方式实现,比如:音视频转换 ...

  2. php 获取压缩包名

    参考链接: https://segmentfault.com/q/1010000000721799 通过curl方式获取压缩包名: function getFile($url, $save_dir = ...

  3. django学习~models之查询

    一 简介:今天学习models查询的一些东西 二 理解概念 Queryset 定义 从数据库中查询出来的结果一般是一个集合,这个集合叫做 QuerySet 三 细节学习 一 常用的models函数 . ...

  4. python - 发送邮件(email模块(内置))

    发送邮件 import smtplib from email.mime.text import MIMEText #邮箱件内容 HTML = """ 发送邮件测试2,加密 ...

  5. CentOS7_JDK安装和环境变量配置

    1.下载 curl -O http://download.Oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz 2.改名 mv ...

  6. Linux Makefile 中的陷阱【转】

    转自:https://blog.csdn.net/QQ1452008/article/details/52247944 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog. ...

  7. Intellij IDEA14 搜索框及控制台乱码解决

    搜索ctrl+F及ctrl+H的搜索框.调试的时候控制台.导入module都显示为为中文乱码 如下: 解决方案: File->Setting->IDE Settings->Appea ...

  8. Hive官方使用手册——新Hive CLI(Beeline CLI)

    Hive官方使用手册——新Hive CLI(Beeline CLI) https://blog.csdn.net/maizi1045/article/details/79481686

  9. h5新API之WebStorage解决页面数据通信问题

    localStorage相信大家都不陌生,今天我们要讨论的不是怎么存储数据,获取数据.而是看看WebStorage的一些妙用,相信大家在开发中遇到过这样一个场景,一个页面中嵌套一个iframe,ifr ...

  10. 调试Windows Service

    调试Windows Service 使用一般的调试方法调试不了Windows Servers,所以参考了一些调试方法 我服务源码中使用了Timer,注意不能使用工具箱内的Timer,用System.T ...