Spring-Boot-Starter 学习笔记(1)
Spring-Boot-Starter
1. 准备配置类和 Bean 对象
Spring Boot 提供了两个注解:
@Configuration:Spring 提供的配置类注解,作用在类上,代表整个类是个 Spring 配置类,对照传统的 Spring XML 配置文件。@Bean:作用于方法上,代表此方法的返回值(对象)将会被 Spring 容器所管理,从而完成 Bean 的自动注册。
这两个组合起来搭配可以完美的代替传统的 Spring XML 配置文件,并给 Spring Boot 的自动配置提供基本数据体。
2. 自动配置条件依赖
有些情况下自动配置类并不是在任何条件下都能生效的,此时我们需要制定自动配置生效的条件,可以使用 Spring Boot 提供的注解来指定生效条件。
这些注解是 spring boot 特有的,常见的条件依赖注解有:
| 注解 | 功能说明 |
|---|---|
| @ConditionalOnBean | 仅在当前上下文中存在某个 bean 时,才会实例化这个 Bean |
| @ConditionalOnClass | 某个 class 位于类路径上,才会实例化这个 Bean |
| @ConditionalOnExpression | 当表达式为 true 的时候,才会实例化这个 Bean |
| @ConditionalOnMissingBean | 仅在当前上下文中不存在某个 bean 时,才会实例化这个 Bean |
| @ConditionalOnMissingClass | 某个 class 在类路径上不存在的时候,才会实例化这个 Bean |
| @ConditionalOnNotWebApplication | 不是 web 应用时才会实例化这个 Bean |
| @AutoConfigureAfter | 在某个 Bean 完成自动配置后实例化这个 Bean |
| @AutoConfigureBefore | 在某个 Bean 完成自动配置前实例化这个 Bean |
3. Bean 的参数获取
举个例子,例如在 Spring Boot Web 项目中,我们经常会导入 MyBatis 相关的依赖,帮助我们与数据库打交道,那么在传统的 Spring 项目中,我们一般会在 Spring 容器配置 XML 文件中去使用 <bean> 标签生成相关数据源(DataSource),那么这个 DataSource 需要我们提供数据库连接参数:driver、url、username、password 这四个最基本的参数,这些数据可能放在一个叫做 db.properties 文件中,这种文件我们称为外部数据源文件,在 Spring 配置文件中声明:<context:property-placeholder location="classpath:db.properties"/>
这样就可以引入文件中的配置参数了,从而赋值给 DataSource 这个 Bean 所需要的属性参数。最后完成对象初始化。
这个过程在传统 Spring 开发,无疑是略显繁琐,如果在某些我们需要自定义类和大量参数属性从外部文件引入,这个时候 properties 文件格式也比较复杂,文件可能较多,在初始化 Bean 时,需要手写大量的属性赋值。
那么 Spring Boot 提供了注解帮助我们减小开发量,更加规范 Bean 参数的获取方式。
默认情况下我们 Bean 的参数配置在 application.yml 文件中,使用 YAML 文件格式定义,比 properties 文件更有层级感,更简约。
搭配 @EnableConfigurationProperties、@ConfigurationProperties 这两个注解可以直接实现自动配置类的 Bean 参数获取。
3.1 @EnableConfigurationProperties 注解
这个注解使用情况:自动配置类中需要从外部文件获取参数,来进行初始化。
在注解中指定一个类,这个时候可以配置类可以在这个类中获取到外部文件的参数,交给配置类中的 Bean 进行初始化。
3.2 @ConfigurationProperties 注解
注解使用情况:从外部文件获取参数信息,加载到自身类属性中,给 Spring 配置类提供外部数据来源,外部数据文件通常指的是 application.yml。
在注解中指定从 application.yml 文件获取的前缀,例如 @ConfigurationProperties(prefix="spring.datasource"),会获取以这个字符串为前缀的所有参数进行自动匹配赋值。
所以可以看出两个注解的关系是:
@EnableConfigurationProperties 注解作用在配置类中,并且使得该注解指定的数据文件类中的 @ConfigurationProperties 注解生效。
4. Bean 的发现
4.1 自己项目的 Bean 扫描
在写 Spring Boot 项目时,一般在项目的代码的根目录会有一个 Spring Boot 启动类:xxxApplication.java,这个类被 @SpringBootApplication 注解修饰标记成 Spring Boot 项目的启动类。
@SpringBootApplication
public class SpringbootStarterApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootStarterApplication.class, args);
}
}
此时再来看看如何完成 Bean 扫描,我们需要查看 @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}
)}
)
public @interface SpringBootApplication {
//...
}
我们重点查看 @SpringBootConfiguration 注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
可以看到这个注解被熟悉的 @Configuration 注解修饰。@SpringBootConfiguration 应用标注在某个类上说明这个类是SpringBoot 的主配置类,SpringBoot 需要运行这个类的 main 方法来启动 SpringBoot 应用。
底层 Spring Boot 会帮我们将启动类的当前路径包以及子包的所有 Spring 组件(可能需要 @ComponentScan注解去做组件扫描)以及 Bean 扫描初始化。暂时只说浅层的流程,后续会深入 Spring 源码学习。
4.2 jar 包的 Bean 扫描
那么前面聊了自己项目的 Bean 扫描,且 Spring Boot 默认扫描启动类所在包下的主类与子类的所有组件,其中并没有包括项目依赖包中的类,那么这些类是如何被 Spring Boot 发现的呢?
这就是第二个主要注解:@EnableAutoConfiguration,开启自动配置:
这里引入其他博客的理解,觉得这几句话简单易懂:
一、
@EnableAutoConfiguration的作用
简单点说就是 Spring Boot 根据依赖中的 jar 包,自动选择实例化某些配置,配置类必须有@Configuration注解。说白了,还是实例化对象,只是实例化的是依赖包中的类。
另外,我们也可以按照自动装配的规范自己定义装配的类。
接下来查看一下注解源码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
//...
}
主要看 @Import({AutoConfigurationImportSelector.class}),这个注解导入了 AutoConfigurationImportSelector.class 这个类(如果是其他版本,可能会是 @EnableAutoConfigurationImportSelector 这个是子类)。

我们找到 getCandidateConfigurations() 方法,这个方法就是用来加载依赖所需要的自动配置相关。
看到 SpringFactoriesLoader.loadFactoryNames() 的源码:

其他版本可能是只有 loadFactoryNames() 方法,但是我们主要关注 classLoader.getResources() 方法中的常量:

很明显这个方法是用来加载资源文件,而这个 Spring 工厂资源的路径就是依赖中自动配置的相关路径,根据这个路径找到需要自动配置的类,最后完成依赖的自动配置。我们导入 mybatis-spring-boot-starter 依赖看看这个 META-INF/spring.factories 里边是怎么样的:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
简单概括的流程:Spring Boot 会根据 jar 包的 META-INF/spring.factories 文件的配置进行自动装配,装配的流程是 SpringFactoriesLoader.loadFactoryNames() 方法顶层实现的(底层实现需深入源码),而开始外部自动装配的注解是:@SpringBootApplication 注解中的 @Import({AutoConfigurationImportSelector.class})
主导整个过程。
5. Bean 的加载
在 Spring Boot 中将一个普通类交给 Spring 容器管理,通常有以下几个方法:
- 使用
@Configuration配合@Bean注解使用(配置类)。 - 使用
@Controller、@Service、@Repository、@Component注解标注类并且使用@ComponentScan自动扫描(组件扫描)。 - 使用
@Import方法(加载外部依赖的类)。
在上面可以看到 Spring Boot 实现自动配置使用的是 @Import 注解这种方式。AutoConfigurationImportSelector 类的 selectImports() 方法(其中调用了 getAutoConfigurationEntry() 方法主要过程)返回一组从 META-INF/spring.factories 文件中读取的 Bean 的全限定名,这样 Spring Boot 就可以加载到这些 Bean 并完成实例的初始化工作。
自动配置总结
经过前面的分析,将自动配置的关键步骤以及对应注解抽取出来:
- 定义需要自动装配的类信息:
@Configuration、@Bean,Spring Boot 配置类。 - 设置自动配置条件依赖:
@Conditional。 - 将外部配置文件读取并封装成 Bean,让配置类读取参数:
@EnableConfigurationProperties、@ConfigurationProperties。 - 实现 Bean 的发现与加载:
@EnableAutoConfiguration、@Import。
以上的内容是基于其他相关博客内容的基础,进行自己的学习记录,接下来需要自定义一个 Spring Boot Starter 来进一步加深理解,后续可能还需要对 Spring 、Spring Boot 的源码进行学习。
Spring-Boot-Starter 学习笔记(1)的更多相关文章
- Spring Boot 入门学习笔记
0x01 前言 大一选修课C++/JAVA二选一,选学了C++.但在后续课程中,发现JAVA的用途很多,所以简单学习了JAVA的语法.同时,也开始了我的Spring Boot 春季|家 (spri ...
- Spring BOOT的学习笔记
1,静态文件夹src/main/resources/static下的,图片必须放在images文件夹下才能访问,直接放在static下不能访问 2,配置热部署,否则修改下Html,图片都得重启 htt ...
- Spring boot + jdbc学习笔记
pom.xml: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www. ...
- Spring Boot + WebSocket 学习笔记
首先需要了解一下背景,什么是WebSocket以及为什么要用WebSocket. 在常见的Web应用中,客户端与服务器通信,都是通过HTTP协议进行通信,客户端一次请求,服务端一次响应.而WebSoc ...
- Spring boot ----RestTemplate学习笔记
****spring boot-----restTemplate 封装了HttpURLConnection,HttpClient,Netty等接口访问实现库 restTemplet包含以下部分 Htt ...
- 自己写spring boot starter
自己写spring boot starter 学习了:<spring boot实战>汪云飞著 6.5.4节 pom.xml <project xmlns="http://m ...
- spring cloud(学习笔记)高可用注册中心(Eureka)的实现(二)
绪论 前几天我用一种方式实现了spring cloud的高可用,达到两个注册中心,详情见spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一),今天我意外发现,注册中心可以无限 ...
- Spring Boot的学习之路(02):和你一起阅读Spring Boot官网
官网是我们学习的第一手资料,我们不能忽视它.却往往因为是英文版的,我们选择了逃避它,打开了又关闭. 我们平常开发学习中,很少去官网上看.也许学完以后,我们连官网长什么样子,都不是很清楚.所以,我们在开 ...
- 手把手教你定制标准Spring Boot starter,真的很清晰
写在前面 我们每次构建一个 Spring 应用程序时,我们都不希望从头开始实现具有「横切关注点」的内容:相反,我们希望一次性实现这些功能,并根据需要将它们包含到任何我们要构建的应用程序中 横切关注点 ...
- 年轻人的第一个自定义 Spring Boot Starter!
陆陆续续,零零散散,栈长已经写了几十篇 Spring Boot 系列文章了,其中有介绍到 Spring Boot Starters 启动器,使用的.介绍的都是第三方的 Starters ,那如何开发一 ...
随机推荐
- Go语言中的结构体:灵活性与可扩展性的重要角色
1. 引言 结构体是Go语言中重要且灵活的概念之一.结构体的使用使得我们可以定义自己的数据类型,并将不同类型的字段组合在一起,实现更灵活的数据结构.本文旨在深入介绍Go语言中的结构体,揭示其重要性和灵 ...
- HiveSQL在使用聚合类函数的时候性能分析和优化详解
概述 前文我们写过简单SQL的性能分析和解读,简单SQL被归类为select-from-where型SQL语句,其主要特点是只有map阶段的数据处理,相当于直接从hive中取数出来,不需要经过行变化. ...
- 前端Vue自定义导航栏菜单 定制左侧导航菜单按钮 中部logo图标 右侧导航菜单按钮
前端Vue自定义导航栏菜单 定制左侧导航菜单按钮 中部logo图标 右侧导航菜单按钮, 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin? ...
- 【linux命令】最强大的编辑器vim用法简介(基础篇)
vim编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器.它主要分为命令令行模式.插入模式和底行模式这三种,下面主要介绍一下这三种模式最简单常用的用法. 一.命令 ...
- RSA 加密签名验签解密
import javax.crypto.Cipher; import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.spec.PSo ...
- 电子表格vlookup函数使用
vlookup是常用的辅助查找函数,但是这个函数的参数定义和解释非常的难以理解,即使用向导也很难搞清楚哪个参数是啥意思.放到编程圈里面应该也算bad design的典型了.下面是函数的定义,每次看到这 ...
- Redis和Mysql保持数据一致性
1.简述 在高并发的场景下,大量的请求直接访问Mysql很容易造成性能问题.所以,我们都会用Redis来做数据的缓存,削减对数据库的请求.但是,Mysql和Redis是两种不同的数据库,如何保证不 ...
- 【MAUI Blazor踩坑日记】4.只在特定平台上引用包
其实这个并不是MAUI特有的问题,只是在MAUI中可能会遇到. 例如某个包只在Windows上有用,但打包的时候,安卓.ios也会把这个包计算在内 所以需要在不是特定平台时把它排除. 万幸从微软文档找 ...
- Unsupervised Learning of Depth and Ego-Motion from Video(CVPR2017)论文阅读
深度估计问题 从输入的单目或双目图像,计算图像物体与摄像头之间距离(输出距离图),双目的距离估计应该是比较成熟和完善,但往单目上考虑主要还是成本的问题,所以做好单目的深度估计有一定的意义.单目的意思是 ...
- 解读 --- System.Windows.Forms.Timer是前台线程吗?
引言 今天同事问了我一个问题,System.Windows.Forms.Timer是前台线程还是后台线程,我当时想的是它是跟着UI线程一起结束的,应该是前台线程吧? 我确实没有仔细研究过他们的异同,所 ...