如何理解Spring Boot自动配置原理和应用?

我们知道,基于Spring Boot,我们只需要在类路径中引入一组第三方框架的starter组件,就能在Spring容器中使用这些框架所提供的各项功能。这在当下的开发过程中已经习以为常,但在Spring Boot还没有诞生之前却是不可想象的。如果我们使用传统的Spring框架,那就需要添加各种繁杂的配置信息才能启动容器。那么,Spring Boot是通过那种机制来做到这一点的呢?这就是今天我们要讨论的内容,即Spring Boot的自动配置机制。

可以说,Spring Boot的自动配置机制应用也非常广泛,在目前主流的开源框架中,都提供了各自的starter组件。例如,Mybatis的starter组件为mybatis-spring-boot-starter。而从扩展性上讲,这也是Spring Boot为开发人员提供了一整套扩展机制,我们可以基于这套扩展机制实现自定义的starter组件。

Spring Boot自动配置机制原理

Spring Boot的自动配置功能强大,但也有一定的复杂度,让我们先来深入理解其背后的实现原理。

@EnableAutoConfiguration注解

我们通过查看@SpringBootApplication注解的定义,发现该注解实际上是一个复合注解,由@SpringBootConfiguration、@ComponentScan和@EnableAutoConfiguration所组成。


我们知道@ComponentScan是传统Spring框架中就内置的注解,而@SpringBootConfiguration注解也很简单,实际上只是对Spring框架中另一个常用组件@Configuration的一种包装,本身没有定义任何内容。所以,我们接下来重点剖析@EnableAutoConfiguration注解。

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import(AutoConfigurationImportSelector.class)

public @interface EnableAutoConfiguration {

String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

Class<?>[] exclude() default {};

String[] excludeName() default {};

}

可以看到,这里出现了一个新的注解,即@AutoConfigurationPackage。从命名上讲, @AutoConfigurationPackage注解的作用就是自动对某一个代码包进行配置。

另一方面,我们还看到通过@Import注解引入了一个AutoConfigurationImportSelector对。从命名上,我们也不难理解该类的作用是完成对导入的配置信息的自动选择。该类的核心方法getCandidateConfigurations实现了这一目标

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

return configurations;

}

这里引出了在Spring Boot中真正负责加载配置信息的SpringFactoriesLoader类。

这些类之间的交互关系如下图所示。


显然,想要完成配置信息的自动选择,我们首先需要执行配置文件的加载操作,这部分功能是由SpringFactoriesLoader来完成的。SpringFactoriesLoader也是Spring Boot自动配置得以实现的关键组件,我们来一起看一下。

SpringFactoriesLoader

SpringFactoriesLoader类似JDK中的SPI机制所使用的ServiceLoader类,区别只是在配置文件的存放位置和配置项对应的键值定义。在SpringFactoriesLoader中,我们需要通过META-INF/spring.factories文件夹获取服务定义文件,并通过EnableAutoConfiguration这个健值来获取具体的配置信息。下图展示了SpringFactoriesLoader和ServiceLoader之间的区别。


SpringFactoriesLoader基于上图中指定的配置文件名和键值获取对应的配置信息,然后基于这些配置信息来实例化配置类,Spring Boot通过反射机制实现了这一目标。SpringFactoriesLoader类中的loadSpringFactories方法展示了这一过程。

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {

//从缓存中获取配置内容,如果存在则直接返回

try {

//基于ClassLoader从META-INF/spring.factories获取配置文件资源地址URL

while (urls.hasMoreElements()) {

//获取配置文件资源

//加载配置项

for (Map.Entry<?, ?> entry : properties.entrySet()) {

//组装配置项Key-Value

}

}

//把配置信息放入缓存

//返回结果

}

}

我们在spring-boot-autoconfigure工程中所使用的spring.factories配置文件中知道了如下所示配置项。

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\

org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\

org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\

可以看到在org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项中定义了各种以-AutoConfiguration结尾的配置类。通过SpringFactoriesLoader,Spring Boot就能做到在服务启动的过程中把它们记载到容器中并实现自动化配置。

Mybatis Spring Boot Starter

介绍完Spring Boot中应用程序的自动配置机制之后,我们来做一些实践,通过剖析Mybatis Spring Boot Starter的启动过程来加深对所介绍内容的理解。

在mybatis-spring-boot-starter中存在几个代码工程,我们重点关注mybatis-spring-boot-autoconfigure工程。而在这个代码工程中,最重要的显然就是MybatisAutoConfiguration类。对于Spring Boot中的AutoConfiguration类,我们首先需要重点关注的是类定义上的注解,如下所示。

@org.springframework.context.annotation.Configuration

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })

@ConditionalOnSingleCandidate(DataSource.class)

@EnableConfigurationProperties(MybatisProperties.class)

@AutoConfigureAfter(DataSourceAutoConfiguration.class)

public class MybatisAutoConfiguration implements InitializingBean {

我们看到这里用到了新的@ConditionalOnClass和@ ConditionalOnSingleCandidate注解,它们就是Spring Boot中的条件注解。在介绍MybatisAutoConfiguration之前,有必要对这些注解做一定展开。

@ConditionalOn系列条件注解

我们在前面的介绍中已经了解到以-AutoConfiguration结尾的自动配置类数量会很多,在一个应用程序的开发过程中,我们通常不会全部使用到。这时候就需要引入一种机制来对这些自动配置类进行过滤。为此,Spring Boot提供了一组@ConditionalOn系列条件注解。通这些注解,我们就可以基于特定的条件来选择性的加载某些配置类。在Spring Boot中常见的条件注解可以参考下图。


在前面介绍的MybatisAutoConfiguration类上,我们发现了@ConditionalOnClass和@ConditionalOnSingleCandidate这两个条件注解。基于这两个条件注解,我们可以明确MybatisAutoConfiguration能够实例化的前提有两个,一个是类路径中存在SqlSessionFactory和SqlSessionFactoryBean,另一个是容器中只存在一个DataSource实例。两者缺一不可,这是一种常用的自动配置控制技巧。

然后,我们在MybatisAutoConfiguration类上看到了一个@EnableConfigurationProperties注解。通过这个注解,所有添加了@ConfigurationProperties 注解的配置类就会自动生效。这里的@EnableConfigurationProperties注解中指定的是MybatisProperties类,该类定义了Mybatis运行时所需要的各种配置信息,而我们在MybatisProperties类上确实也发现了@ConfigurationProperties注解,并指定了prefix为"mybatis"。

@ConfigurationProperties(

     prefix = "mybatis"

)

public class MybatisProperties {

...

}

最后,在MybatisAutoConfiguration类上还存在一个@AutoConfigureAfter注解,这个注解可以根据字面意思进行理解,即在完成某一个类的自动配置之后再执行当前类的自动配置,这个需要提前装配的类指的就是DataSourceAutoConfiguration。

MybatisAutoConfiguration

理解上@ConditionalOnXXX、@EnableConfigurationProperties和@AutoConfigureAfter等一系列注解之后,我们回过头来再看MybatisAutoConfiguration类的代码结构就显得比较简单明了。MybatisAutoConfiguration类中核心方法之一就是如下所示的sqlSessionFactory方法。

@Bean

@ConditionalOnMissingBean

public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {

    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();

    factory.setDataSource(dataSource);

    factory.setVfs(SpringBootVFS.class);

    if (StringUtils.hasText(this.properties.getConfigLocation())) {

      factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));

    }

    applyConfiguration(factory);

    

    //省略一系列配置项设置方法    

    return factory.getObject();

}

显然,这里基于前面介绍的SqlSessionFactoryBean构建了SqlSessionFactory实例。注意到在该方法上同样添加了一个@ConditionalOnMissingBean注解,标明只有在当前上下文中不存SqlSessionFactoryBean对象时才会执行上述方法。

同样添加了@ConditionalOnMissingBean注解的还有如下所示的sqlSessionTemplate方法。

@Bean

@ConditionalOnMissingBean

public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {

    ExecutorType executorType = this.properties.getExecutorType();

    if (executorType != null) {

      return new SqlSessionTemplate(sqlSessionFactory, executorType);

    } else {

      return new SqlSessionTemplate(sqlSessionFactory);

    }

}

该方法用于构建一个SqlSessionTemplate对象实例。在Mybatis中,SqlSessionTemplate实现了SqlSession接口,相当于是全局唯一的SqlSession实例。

接下来,我们需要在META-INF/spring.factories文件中明确所指定的自动配置类。根据Spring Boot自动配置机制的原理,对于mybatis-spring-boot-autoconfigure工程而言,这个配置项内容应该如下所示。

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

至此,整个Mybatis Spring Boot Starter的介绍就告一段落。作为总结,我们可以把创建一个Spring Boot Starter的过程抽象三个步骤。


在日常开发过程中,我们就可以基于这三大步骤来实现一个自定义的Spring Boot Starter。

今天的内容详细阐述了Spring Boot自动配置机制的实现原理,从源码角度分析了为什么Spring Boot能够做到自动配置,并结合Mybatis框架分析了它在开源框架中的具体应用。同时,我们在本讲结尾部分还总结了开发一个Spring Boot Starter的三大步骤,开发一个Spring Boot Starter也是常见的需求,我们在开发过程中可以基于本讲的内容加深对其实现原理的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/17186.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

这款信创FTP软件,可实现安全稳定的文件传输

信创&#xff0c;即信息技术应用创新&#xff0c;2018年以来&#xff0c;受“华为、中兴事件”影响&#xff0c;国家将信创产业纳入国家战略&#xff0c;并提出了“28n”发展体系。“8”具体指金融、石油、电力、电信、交通、航空航天、医院、教育等主要行业。目前企业使用比较…

0527_C++1

练习1&#xff1a; 定义自己的命名空间my_sapce&#xff0c;在my_sapce中定义string类型的变量s1&#xff0c;再定义一个函数完成对字符串的逆置。 #include <iostream>using namespace std; namespace my_space {string s1"hello world";void my_strreverse…

对比表征学习(一)Contrastive Representation Learning

对比表征学习&#xff08;二&#xff09;Sentence Embedding 主要参考翁莉莲的Blog&#xff0c;本文主要聚焦于对比损失函数 对比表示学习&#xff08;Contrastive Representation Learning&#xff09;可以用来优化嵌入空间&#xff0c;使相似的数据靠近&#xff0c;不相似的数…

数据结构(四)双向链表

文章目录 一、概念二、无头双向链表示意图三、操作&#xff08;一&#xff09;定义结构体&#xff08;二&#xff09;创建链表1. 函数定义2. 注意点3. 代码实现 &#xff08;三&#xff09;插入1. 函数定义2. 注意点3. 代码实现 &#xff08;四&#xff09;删除1. 函数定义2. 注…

B端:ElementUI、AntDesign、若依等看腻了,来点不一样的。

现在对ElementUI、AntDesign和若依这些 UI 框架感到厌倦了&#xff0c;本次给大家分享一些更加个性化的UI界面。

干货|图生代码实例整理,让你的代码更高效

前言 “图生代码”。这项新功能允许开发人员直接利用产品设计图一键生成相应的代码&#xff0c;极大地提高了编程效率和研发速度。甚至会未来软件开发可能迎来一场革命性的变革。但图生代码究竟能直到什么程度&#xff1f;本文结合一款图生代码的实例程序整理了一些有代表意义…

C语言 数组——排序算法的函数实现

目录 交换法排序 用交换法对成绩数组升序排序 选择法排序 冒泡法排序 归并法排序 交换法排序 用交换法对成绩数组升序排序 选择法排序 冒泡法排序 归并法排序

期望薪资30k字节java2面,A给B转账的同时B给A转账怎么并发量最高

一面 1、自我介绍 2、详细介绍一下自己的做的项目&#xff1f;根据项目提了一些问题 3、hashmap原理 4、B树原理&#xff1f; 5、final禁止重排序原理&#xff1f; 6、设计一个榨汁机类&#xff0c;面向对象怎么设计&#xff1f; 7、get、post区别&#xff0c;使用场景&…

已解决ModuleNotFoundError : No module named ‘pandas亲测有效!!!

已解决ModuleNotFoundError : No module named ‘pandas亲测有效&#xff01;&#xff01;&#xff01; 亲测有效 报错问题解决思路解决方法 报错问题 在运行Python代码时&#xff0c;你可能会遇到以下报错信息&#xff1a; ModuleNotFoundError: No module named pandas这个…

华为昇腾310B初体验,OrangePi AIpro开发板使用测评

0、写在前面 很高兴收到官方的OrangePi AIpro开发板测试邀请&#xff0c;在过去的几年中&#xff0c;我在自己的博客写了一系列有关搭载嵌入式Linux系统的SBC&#xff08;单板计算机&#xff09;的博文&#xff0c;包括树莓派4系列、2K1000龙芯教育派、Radxa Rock5B、BeagleBo…

攒粒是什么?怎么用攒粒赚钱?

攒粒简介 攒粒的前身是91问问&#xff0c;隶属于上海道道永泉市场调查有限公司&#xff0c;是一家专业的全球在线调研服务公司&#xff0c;也是是国内排名前列的社区调查之一&#xff0c;10年在线调研&#xff0c;600万会员亲身体验&#xff0c;提供网络调查、市场调查、问卷调…

KT6368A蓝牙芯片AT命令会被透传出去,指令对为什么会被透传出去

一、简介 KT6368A再被连接之后&#xff0c;AT命令会被透传出去。被透传的这组AT命令是符合文档要求&#xff0c;不应被透传&#xff0c;实际却经常被透传。并且可以每次都复现 详细描述 有问题部分的串口数据监控结果如下&#xff1a;其中41 54 2B 42 4D 46 30 41 46 42 43 3…

从零自制docker-15-【实现 mydocker run -d 支持后台运行容器】

文章目录 实现目的莫名奇妙的问题对之前upper层出现root补充对run某些命令出现找不到文件或目录的原因代码效果 实现目的 docker run -d时容器在后台运行&#xff0c;而不会进入命令行交互形式 首先是需要添加-d选项然后设置当添加-d选项时候主进程不会等待子进程&#xff0c…

Rocky Linux 9.4 正式版发布 - RHEL 100% 1:1 兼容免费发行版

Rocky Linux 9.4 正式版发布 - RHEL 100% 1:1 兼容免费发行版 Rocky Linux 由 CentOS 项目的创始人 Gregory Kurtzer 领导 请访问原文链接&#xff1a;Rocky Linux 9.4 正式版发布 - RHEL 100% 1:1 兼容免费发行版&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处…

GPT-4o: 未来的智能助手

GPT-4o: 未来的智能助手 在这个信息爆炸的时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为我们生活中不可或缺的一部分。作为OpenAI最新推出的语言模型&#xff0c;GPT-4o不仅继承了前几代模型的优点&#xff0c;还在多个方面进行了显著的提升。本文将带你深入了解…

DreamerV3阅读笔记

DreamerV3 文章希望解决的一个挑战是用固定的hyperparameter来同时处理不同domain的任务。文章发现&#xff0c;通过结合KL balancing 和free bits可以使得world model learn without tuning&#xff08;是指上面这件事&#xff0c;即不需要对不同任务改变hyperparameter&#…

2024年电工杯高校数学建模竞赛(B题) 建模解析| 大学生平衡膳食食谱的优化设计

问题重述及方法概述 问题1&#xff1a;膳食食谱的营养分析评价及调整 数学方法&#xff1a;线性规划模型、营养素评价模型、比较分析 可视化数据图&#xff1a;营养素含量表、营养素摄入量对比图、营养素缺乏情况图 问题2&#xff1a;基于附件3的日平衡膳食食谱的优化设计 数…

KingbaseES数据库物理备份还原sys_rman

数据库版本&#xff1a;KingbaseES V008R006C008B0014 简介 sys_rman 是 KingbaseES 数据库中重要的物理备份还原工具&#xff0c;支持不同类型的全量备份、差异备份、增量备份&#xff0c;保证数据库在遇到故障时及时使用 sys_rman 来恢复到数据库先前状态。 文章目录如下 1.…

揭秘爬虫技术:从请求到存储的全方位解析

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、爬虫初探&#xff1a;请求与响应 二、数据解析&#xff1a;从混乱中提炼价值 三、数据…

Megatron-LM源码系列(八): Context Parallel并行

1. Context Parallel并行原理介绍 megatron中的context并行(简称CP)与sequence并行(简称SP)不同点在于&#xff0c;SP只针对Layernorm和Dropout输出的activation在sequence维度上进行切分&#xff0c;CP则是对所有的input输入和所有的输出activation在sequence维度上进行切分&…