SpringBoot的自动装配原理及应用
什么是SpringBoot自动装配
所谓的“SpringBoot自动装配”就是指:通过注解和一些简单的配置就能将某些组件载入Spring容器环境中,便于使用。
比如,很多spring-boot-starter
组件只要简单引入,然后在SpringBoot的配置文件application.properties
或application.yml
中添加对应的参数配置就可以使用了,非常方便。
实际上,“自动装配”机制是Spring Boot定义的一个规范:SpringBoot在启动时会扫描外部引用jar包中的META-INF/spring.factories
文件,将文件中配置的类信息加载到Spring容器,并执行类中定义的各种操作。对于外部jar来说,只需要按照SpringBoot定义的标准,就能将自己的功能装置进SpringBoot。
那么,这种“自动装配”机制具体是如何实现的呢?
SpringBoot自动装配实现机制
其实,这一切都要从Spring Boot的核心注解@SpringBootApplication
说起。
// 注解@SpringBootApplication的定义
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {}
// 注解@SpringBootConfiguration的定义,本质上就是@Configuration注解的包装
@Configuration
public @interface SpringBootConfiguration {}
// 注解@EnableAutoConfiguration的定义
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
如上,从注解@SpringBootApplication
的定义来看,本质上它是@Configuration
,EnableAutoConfiguration
和@ComponentScan
这三个注解的组合,它们的含义分别是:
- @Configuration:用于在上下文中注册额外的Bean或导入其他配置类
- @EnableAutoConfiguration:启用Spring Boot的自动装配机制
- @ComponentScan:扫描被
@Component
,@Service
,@Controller
等注解的Bean,默认会扫描启动类所在包及其子包下的所有类,可以自定义不扫描某些类
所以,注解@EnableAutoConfiguration
才是实现Spring Boot自动装配的关键。
在注解@EnableAutoConfiguration
中通过@Import
导入了AutoConfigurationImportSelector
类,在这个类中真正实现了从外部jar包的META-INF/spring.factories
文件中读取配置的类信息。
具体来说,是在getCandidateConfigurations()
方法中实现读取配置类的。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 调用SpringFactoriesLoader.loadFactoryNames()方法从文件META-INF/spring.factories中读取配置信息类
List<String> configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
调用关系如下图:
那么,通过AutoConfigurationImportSelector
读取的配置信息类在哪里使用了呢?
实际上,这个需要跟SpringBoot的启动流程关联起来,经过代码追踪可以知道,调用AutoConfigurationImportSelector.getCandidateConfigurations()
方法读取外部文件中的配置类这个操作是在IoC容器的refresh()方法中触发的。也就是说,在IoC容器启动的时候通过调用getCandidateConfigurations()
方法把外部文件中指定的类读取进来,然后再使用反射机制将它们实例化成为Bean对象载入到IoC容器中。
SpringBoot的启动时序图如下所示:
如何Starter组件
既然弄明白了SpringBoot的自动装配机制是什么,即可以很方便地实现一个starter
组件了。
如下示例展示在一个自定义的starter
组件中定义一个访问Redis的客户端组件RedissonClient
。
新建一个artifactId为redisson-spring-boot-starter
的项目,添加依赖:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.chench.extra.spring.boot</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.1.RELEASE</version>
<!-- 禁止传递依赖 -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.1</version>
</dependency>
<!-- 配置参数提示,需加此依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
</dependencies>
</project>
新一个保存配置参数信息的类RedissonProperties
,用于从Spring Boot配置文件中加载以auto.redisson
为前缀的参数。
// 从SpringBoot配置文件中读取以`auto.redisson`为前缀的参数,如:auto.redisson.host=127.0.0.1
@ConfigurationProperties(prefix = "auto.redisson")
public class RedissonProperties {
private String host = "localhost";
private int port = 6379;
private int timeout = 1000;
private boolean ssl = false;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public boolean isSsl() {
return ssl;
}
public void setSsl(boolean ssl) {
this.ssl = ssl;
}
}
新建一个创建RedissonClient
对象的配置类:
@ConditionalOnClass(Redisson.class) // 使用条件注解,只有当依赖了Redisson时才加载到容器
@EnableConfigurationProperties(RedissonProperties.class) // 加载配置参数类
@Configuration // 这是一个配置类
public class RedissionAutoConfiguration {
@Bean // 实例化RedissonClient对象
public RedissonClient redissonClient(RedissonProperties redissonProperties) {
Config config = new Config();
String prefix = redissonProperties.isSsl() ? "rediss://" : "redis://";
String host = redissonProperties.getHost();
int port = redissonProperties.getPort();
int timeout = redissonProperties.getTimeout();
config.useSingleServer()
.setAddress(prefix + host + ":" + port)
.setTimeout(timeout);
return Redisson.create(config);
}
}
根据SpringBoot自动装配的规范要求,需要在文件META-INF/spring.factories
文件添加需要自动装配的类。
所以新建文件src\main\resources\META-INF\spring.factories
,在文件中添加自动装配的类信息:
# 自动装配的类可以是多个,用英文逗号分隔,使用\进行换行
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.chench.extra.spring.boot.redisson.RedissionAutoConfiguration
至此,一个支持在SpringBoot中进行自动装配的starter
组件基本功能就开发完毕了,执行mvn clean install
将项目打包安装到本地Maven仓库,然后就可以在SpringBoot项目中引入该starter
组件进行使用了。
但是,如果希望在SpringBoot配置文件中添加配置参数时能进行提示,如下图:
还需要在src\main\resources\META-INF\
路径下添加一个配置文件additional-spring-configuration-metadata.json
,内容如下:
{
"properties": [
{
"name": "auto.redisson.host",
"type": "java.lang.String",
"description": "redis服务器地址.",
"defaultValue": "localhost"
},{
"name": "auto.redisson.port",
"type": "java.lang.Integer",
"description": "redis服务器端口.",
"defaultValue": 6379
},{
"name": "auto.redisson.ssl",
"type": "java.lang.Boolean",
"description": "是否使用ssl协议.",
"defaultValue": false
}, {
"name": "auto.redission.timeout",
"type": "java.lang.Integer",
"description": "超时时间.",
"defaultValue": 1000
}
]
}
再另一个项目中直接引入这个自定义的starter
组件使用其中定义的RedissonClient
组件即可。
<!-- 引入自定义的starter组件 -->
<dependency>
<groupId>org.chench.extra.spring.boot</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
在SpringBoot配置文件application.properties
中添加配置参数:
auto.redisson.host=192.168.2.24
auto.redisson.port=6379
auto.redission.timeout=1000
auto.redisson.ssl=false
直接引用自定义组件中的RedissonClient
组件:
// 直接依赖一个在starter中定义的Bean
@Autowired
RedissonClient redissonClient;
private void execute() {
long now = new Date().getTime();
this.redissonClient.getBucket("now").set(now);
}
【参考】
淘宝一面:“说一下 Spring Boot 自动装配原理呗?
Spring和SpringBoot自动装配原理
Spring Boot自动装配原理与启动过程详解
SpringBoot的自动装配原理及应用的更多相关文章
- 【springboot】自动装配原理
摘自:https://mp.weixin.qq.com/s/ZxY_AiJ1m3z1kH6juh2XHw 前言 Spring翻译为中文是"春天",的确,在某段时间内,它给Java开 ...
- SpringBoot启动流程分析(五):SpringBoot自动装配原理实现
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot自动装配原理解析
本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等 我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序: @SpringBoo ...
- springboot自动装配原理
最近开始学习spring源码,看各种文章的时候看到了springboot自动装配实现原理.用自己的话简单概括下. 首先打开一个基本的springboot项目,点进去@SpringBootApplica ...
- springboot自动装配原理,写一个自己的start
springboot自动装配原理 第一次使用springboot的时候,都感觉很神奇.只要加入一个maven的依赖,写几行配置,就能注入redisTemple,rabbitmqTemple等对象. 这 ...
- SpringBoot | 2.1 SpringBoot自动装配原理
@ 目录 前言 1. 引入配置文件与配置绑定 @ImportResource @ConfigurationProperties 1.1 @ConfigurationProperties + @Enab ...
- 【Springboot】Springboot自动装配原理
1.核心注解就是 EnableAutoConfiguration 该注解会激活SpringBoot的自动装配功能: 代码如下: @Target(ElementType.TYPE) @Retentio ...
- 深入理解SpringBoot之自动装配
SpringBoot的自动装配是拆箱即用的基础,也是微服务化的前提.其实它并不那么神秘,我在这之前已经写过最基本的实现了,大家可以参考这篇文章.这次主要的议题是,来看看它是怎么样实现的,我们透过源代码 ...
- Eureka 系列(03)Spring Cloud 自动装配原理
Eureka 系列(03)Spring Cloud 自动装配原理 [TOC] 0. Spring Cloud 系列目录 - Eureka 篇 本文主要是分析 Spring Cloud 是如何整合 Eu ...
- Spring Boot系列(二):Spring Boot自动装配原理解析
一.Spring Boot整合第三方组件(Redis为例) 1.加依赖 <!--redis--> <dependency> <groupId>org.springf ...
随机推荐
- [转帖]三篇文章了解 TiDB 技术内幕 - 谈调度
返回全部 申砾产品技术解读2017-06-06 为什么要进行调度 先回忆一下 三篇文章了解 TiDB 技术内幕 - 说存储提到的一些信息,TiKV 集群是 TiDB 数据库的分布式 KV 存储引擎,数 ...
- [转帖]【基础】HTTP、TCP/IP 协议的原理及应用
https://juejin.cn/post/6844903938232156167 前言 本文将持续记录笔者在学习过程中掌握的一些 HTTP .TCP/IP 的原理,以及这些网络通信技术的一些应用场 ...
- [转帖]自动化回归测试工具 —— AREX 上手实践
https://my.oschina.net/arextest/blog/8589156 AREX 是一款开源的自动化测试工具平台,基于 Java Agent 技术与比对技术,通过流量录制回放能力 ...
- [转帖]Spring Cloud Alibaba Nacos 注册中心使用教程
一. 什么是Nacos Nacos是一个更易于构建云原生应用的动态服务发现(Nacos Discovery ).服务配置(Nacos Config)和服务管理平台,集注册中心+配置中心+服务管理于一身 ...
- Linux bridge使用dummy接口调用IPVS的问题
Linux bridge使用dummy接口调用IPVS的问题 在IPVS: How Kubernetes Services Direct Traffic to Pods一文中,作者给出了一个简单的组网 ...
- ToneGenerator Init failed Crash 崩溃
需求需要在扫码时产生一个短促的提示音, 搜了下像这样实现.测试时发现多次扫码后,会触发程序崩溃问题. 异常如下 java.lang.RuntimeException: Init failed at a ...
- 【JS 逆向百例】某公共资源交易网,公告 URL 参数逆向分析
声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 逆向目标 目标:某地公共资 ...
- Python 潮流周刊#22:Python 3.12.0 发布了!!
你好,我是猫哥.这里每周分享优质的 Python.AI 及通用技术内容,大部分为英文.标题取自其中一则分享,不代表全部内容都是该主题,特此声明. 本周刊由 Python猫 出品,精心筛选国内外的 25 ...
- linux虚拟机固定ip
1.查看宿主机IP信息 在windows宿主机上,键盘输入win+r,输出cmd,打开终端命令行: 输入ipconfig /all,查看宿主机IP信息: 2.修改Linux虚拟机的配置文件 Linux ...
- 【七】强化学习、gym学习平台扩充,更好的玩转虚拟环境,关于mujoco、mujoco-py、baselines安装配置
相关文章: [一]gym环境安装以及安装遇到的错误解决 [二]gym初次入门一学就会-简明教程 [三]gym简单画图 [四]gym搭建自己的环境,全网最详细版本,3分钟你就学会了! [五]gym搭建自 ...