Springboot 自动配置浅析
Introduction
我们知道,SpringBoot之所以强大,就是因为他提供了各种默认的配置,可以让我们在集成各个组件的时候从各种各样的配置文件中解放出来。
拿一个最普通的 web 项目举例。我们需要使用 servlet 容器,SpringBoot 就提供了嵌入式的 Tomcat 作为默认容器,不需要一行配置就能直接以最普通的 Java 程序的方式启动:java -jar;接收请求需要一个网络端口,默认配置好8080;处理请求需要 servlet 的多线程特性,默认配置好了最大线程数为200;处理好的请求以Restful 风格返回给调用方,SpringBoot 默认配置好了jackson进行 json 序列化,业务代码需要做的只是返回一个 POJO 对象;连接池直接就默认配置了性能最好的的 Hikari,以及连接池的默认尺寸为10……在一个简单的web应用中,这些配置我们甚至都可能不了解或者没有意识到它们的存在,就可以让程序正常运行。
这就是自动配置的魔力——润物细无声。
那么自动配置是怎么实现的呢?本文就从POM文件和 @SpringBootApplication 注解来简单分析一下自动配置原理。
真的只是简单地,分析一下。
POM文件
环境
- SpringBoot 2.0.6
父项目
在每一个 SpringBoot 项目一开始的 POM 文件中,就有一个父依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
点进artifactId之后来到 spring-boot-starter-parent-2.0.6.RELEASE.pom 文件,这个文件还有一个父依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
再继续点进去来到 spring-boot-dependencies-2.0.6.RELEASE.pom 文件中。在该文件的 <properties> 标签中可以看到各种各样的组件的版本信息, <dependencyManagement> 标签中声明了各个组件的maven坐标信息。其中,我数了一下,在 SpringBoot 2.0.6 中一个有177个带有版本信息的组件名,包括了大家熟悉的 elasticsearch、activemq、redis、kafka等等。
这里(spring-boot-dependencies-2.0.6.RELEASE.pom文件)称为 SpringBoot 的“版本仲裁中心”,它是用来管理 SpringBoot 应用里面的所有依赖版本的地方。 它包含了大部分开发中会用到的一些组件的版本,所以我们导入依赖默认是不需要写版本号的,SpringBoot 会自动帮我们配置需要的版本。这样在引入某个组件的时候不用考虑这个组件和系统中已有的组件兼不兼容之类的问题,避免了烦人的版本冲突问题。(当然,没有在 dependencies里面管理的依赖自然需要声明版本号)
启动器(Starters)
父项目做版本仲裁,那么真正的 jar 包是从哪里导入进来的呢?这就要说到我们的starters了。点开web-starter可以看到它帮我们导入了web模块正常运行所依赖的组件,就不用我们一个一个手动导入了。
所以,所谓的Starters就是一系列依赖描述的组合,我们可以通过导入这些starters就会有相应的依赖了并可以基于他们进行相应的开发
Springboot把开发中中会遇到的场景都抽象成一个个的starter,比如(),只需要在项目里面引入这些starter 相关场景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动器
@SpringBootApplication
一个典型的 springboot 项目的入口类如下所示:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
只要运行main方法就能启动该应用。main 中运行 run 方法时需要传入一个类,这个类正是使用@SpringBootApplication注解标注的类,如果没有这个注解程序是跑不起来的。
这个注解标注在某个类上就说明这个类是 springboot 的主配置类,springboot 就应该运行这个类的 main 方法来启动springboot应用
点开这个注解的源码,可以看到这是一个组合注解,最主要的是这两个注解:
@SpringBootConfiguration@EnableAutoConfiguration
@SpringBootConfiguration 标注在某个类上,表示这是一个 SpringBoot 的配置类,它的底层是@Configuration,属于spring的底层注解,标注了这个注解的类表名这个类是一个配置类,取代以前开发中的xml文件配置,同时也表明这个类是 spring 容器中的组件,受容器管理。
接下来是@EnableAutoConfiguration注解,它的用处是开启自动配置,使用 spring 开发需要手动配置的东西,现在由 springboot 帮我们配置了,具体的实现就是通过这个注解来实现的。该组合注解有两个。
1. @AutoConfigurationPackage
它的 注解中的核心代码是 @Import({Registrar.class})。
@Import 的作用就是为容器中导入一个它指定的组件。
在 Registrar 这个类中有一个方法叫registerBeanDefinitions,用于注册一些 bean 定义信息:
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
打个断点在这一行代码上,运行
(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()
得到的结果是主配置类所在的包名,目的就是将主配置类所在包及下面所有子包里面的所有组件扫描到Spring容器中。同时也说明了,如果在主配置所在包的上层包添加组件的话是不会被扫描到的、不起作用的。
2. @Import({AutoConfigurationImportSelector.class})
该注解导入了一个自动配置的选择器,真正地给容器中导入 springboot 自动帮我们配置好的配置类。在 AutoConfigurationImportSelector 这个选择器中的 getAutoConfigurationEntry 方法中,以全限定类名的方式把所有需要的配置类导入 springboot 容器中。这些全限定类型所在文件路径为:
org/springframework/boot/spring-boot-autoconfigure/2.1.8.RELEASE/spring-boot-autoconfigure-2.1.8.RELEASE.jar!/META-INF/spring.factories
上述两个注解一个负责扫描我们将要加容器中的类,一个加入 springboot 为我们自动配置好的类,springboot 通过这两种方式省略了我们大量的配置工作。
总结
本文从用于maven项目管理的pom.xml文件和标注在启动类上的@SpringBootApplication注解,简单分析了springboot 自动配置的实现。前者通过版本仲裁中心为我们维护项目组件的版本,防止依赖冲突;后者通过在加载程序的时候导入数以百计的自动配置类实现自动配置。
原文发表于:https://pengcheng.site/2019/10/28/springboot-zi-dong-pei-zhi-qian-xi/
Springboot 自动配置浅析的更多相关文章
- SpringBoot自动配置源码调试
之前对SpringBoot的自动配置原理进行了较为详细的介绍(https://www.cnblogs.com/stm32stm32/p/10560933.html),接下来就对自动配置进行源码调试,探 ...
- SpringBoot实战之SpringBoot自动配置原理
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- springboot自动配置源码解析
springboot版本:2.1.6.RELEASE SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfig ...
- 源码学习系列之SpringBoot自动配置(篇一)
源码学习系列之SpringBoot自动配置源码学习(篇一) ok,本博客尝试跟一下Springboot的自动配置源码,做一下笔记记录,自动配置是Springboot的一个很关键的特性,也容易被忽略的属 ...
- 源码学习系列之SpringBoot自动配置(篇二)
源码学习系列之SpringBoot自动配置(篇二)之HttpEncodingAutoConfiguration 源码分析 继上一篇博客源码学习系列之SpringBoot自动配置(篇一)之后,本博客继续 ...
- SpringBoot自动配置原理学习
介绍 构建Springboot项目时我们会创建一个启动类 @SpringBootApplication public class DemoApplication { public static voi ...
- springboot自动配置国际化失效分析
最近在整理springBoot国际化时,发现国际化没有生效,通过报错提示在 MessageTag -> doEndTag处打断点 最后发现messageSource并不是ResourceBund ...
- 这样讲 SpringBoot 自动配置原理,你应该能明白了吧
https://juejin.im/post/5ce5effb6fb9a07f0b039a14 前言 小伙伴们是否想起曾经被 SSM 整合支配的恐惧?相信很多小伙伴都是有过这样的经历的,一大堆配置问题 ...
- 助力SpringBoot自动配置的条件注解ConditionalOnXXX分析--SpringBoot源码(三)
注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 如何分析SpringBoot源码模块及结构?--SpringBoot源码(二) 上一篇分析了SpringBoo ...
随机推荐
- Python实现电子邮件的发送
利用Python smtplib.SMTP类方法来实现电子邮件的发送. 列举SMTP对象常见的方法: sendmail(from, to ,msg[,mopts,ropts]) :将msg从from发 ...
- CH3801Rainbow的信号
Description Freda发明了传呼机之后,rainbow进一步改进了传呼机发送信息所使用的信号.由于现在是数字.信息时代,rainbow发明的信号用N个自然数表示.为了避免两个人的对话被大坏 ...
- 拿起键盘就是干:跟我一起徒手开发一套分布式IM系统
1.引言 老读者应该还记得我在去年国庆节前分享过一篇<技术干货:从零开始,教你设计一个百万级的消息推送系统>,虽然我在文中有贴一些伪代码,依然有些朋友希望能直接分享一些可以运行的源码.好吧 ...
- Fiddler的基本使用
目录 清空历史请求 请求所消耗的时间 发送的数据在 设置fiddler过滤请求 模拟弱网环境 Ctrl+R 拦截数据,拦截数据又称"打断点" fiddler开启的时候就是默认开始抓 ...
- powershell加载EXE进内存运行
当实战中我们想在目标上运行一些相当复杂的功能,这些功能常是 EXE 文件的一部分.我不想直接在目标上放置一个二进制文件,因为这样可能会触发反病毒机制.一个很好的思路就是将二进制文件嵌入到 Powers ...
- 转 NAT技术详解
NAT产生背景 今天,无数快乐的互联网用户在尽情享受Internet带来的乐趣.他们浏览新闻,搜索资料,下载软件,广交新朋,分享信息,甚至于足不出户获取一切日用所需.企业利用互联网发布信息,传递资料和 ...
- 就改了get,却不让我set?——Java内省机制的神奇行为举止一例
[相关类库]org.apache.commons.beanutils.BeanUtils,提供对Java反射和自省API的包装,其中底层使用到了Java的内省方法.[内省的一般应用形式]通过类Intr ...
- 一文详解CentOS6.5搭建DNS服务
本文详细介绍DNS服务在Linux Operation System 中的搭建过程 一.DNS服务器的工作原理 客户机提出域名解析请求,并将该请求发送给本地的域名服务器.当本地的域名服务器收到请求后, ...
- CocosCreator中_worldMatrix到底是什么(下)
Cocos Creator 中 _worldMatrix 到底是什么(下) 1. 摘要 上篇介绍了矩阵的基本知识以及对应图形变换矩阵推倒.中篇具体介介绍了对应矩阵转换成cocos creator代码的 ...
- Vue 的准备
## .es6的基本语法 let---是局部作用于,不会存在变量提升,变量不能重复声明 const--局部作用域,不会存在变量提升 不能重复声明,只声明常亮,不可变的量 ```javasc ...