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

news2024/11/18 5:56:15

我们知道,基于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.coloradmin.cn/o/1710731.html

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

相关文章

Dubbo生态之初识分布式事务

1.分布式事务简介 传统的关系型数据库只能保证单个数据库中多个数据表的事务特性。一旦多个SQL操作涉及到多个数据库&#xff0c;这类的事务就无法解决跨库事务问题。在传统架构下&#xff0c;这种问题出现的情况非常少&#xff0c;但是在分布式微服务架构中&#xff0c;分布式…

java方法负载问题

先介绍一下方法的重载 下面是例子 方法名都为sum而形参是不同的 记住&#xff01; 是否为重载关系 1在同一个类里面 2形参不同&#xff08;与返回值无关&#xff09; 3方法名一样 第一个图为什么错&#xff1f; 答案&#xff1a;虽然在同一个类里面&#xff0c;并且方法名…

3-Django项目继续--初识ModelForm

目录 ModelForm 认识ModelForm 优势 初识Form 初识ModelForm 添加信息 views.py add_student_new.html 修改信息 views.py views.py add_student_new.html ModelForm 认识ModelForm 优势 1、方便校验用户提交的数据 2、页面展示错误提示 3、数据库字段很多的情况…

基于Docker的ROS开发

本文主要介绍如何使用Docker在Windows和Linux环境中部署并使用ROS&#xff0c;通过Docker Container运行ROS&#xff0c;可以方便我们在一个本地环境中运行多个ROS版本。 更多内容&#xff0c;访问专栏目录获取实时更新。 关于ROS的版本 参考ROS1 Distribution Wiki和ROS2 Dis…

SpringBoot项目启动时提示程序包不存在和找不到符号

一、前言 最近接手同事开发的一个Springboot工作项目&#xff0c;从svn上整体拉取下来后&#xff0c;构建完成后&#xff0c;启动的时候遇到了程序包找不到的情况&#xff0c;记录一下处理过程&#xff1b; 二、项目问题 1、报错信息&#xff1a;启动后报 java: 程序包org.sp…

最强端侧多模态模型MiniCPM-V 2.5,8B 参数,性能超越 GPT-4V 和 Gemini Pro

前言 近年来&#xff0c;人工智能领域掀起了一股大模型热潮&#xff0c;然而大模型的巨大参数量级和高昂的算力需求&#xff0c;限制了其在端侧设备上的应用。为了打破这一局限&#xff0c;面壁智能推出了 MiniCPM 模型家族&#xff0c;致力于打造高性能、低参数量的端侧模型。…

【Qt秘籍】[004]-Qt中的重要工具-介绍

QtCreator概览 当我们打开系统的菜单翻到刚刚下载的Qt文件&#xff0c;里面的内容却让我们眼花缭乱。 不过别急&#xff0c;下面我们将一一解析。 1.Assistant Qt自带的离线版本官方文档 2.Designer Qt图形化设计界面的工具&#xff0c;通过拖拽控件快速生成界面&#xff0c…

APM 2.8外置罗盘校准

请注意&#xff1a; GPS不可以飞控带电插拔&#xff0c;带电插拔会产生差分电压&#xff0c;可能会导致GPS模块损坏&#xff0c;无法搜星。不听劝告&#xff0c;后果自负&#xff01; 1.如何接线 GPS有两根线&#xff0c;要插上面图所示的两个接口。同时拔掉旁边的跳线帽&…

强化学习——学习笔记2

在上一篇文章中对强化学习进行了基本的概述&#xff0c;在此篇文章中将继续深入强化学习的相关知识。 一、什么是DP、MC、TD&#xff1f; 动态规划法&#xff08;DP&#xff09;&#xff1a;动态规划法离不开一个关键词&#xff0c;拆分 &#xff0c;就是把求解的问题分解成若…

[AIGC] Nginx常用变量详解

Nginx非常强大&#xff0c;其主要功能包括HTTP服务器、反向代理、负载均衡等。Nginx的配置中有许多内置的变量&#xff0c;你可以在配置文件中使用这些变量进行灵活的配置。在本篇文章中&#xff0c;我们将介绍一些Nginx中常见的变量&#xff0c;包括proxy_add_header。 常见变…

多旋翼无人机机场考哪些内容?

多旋翼无人机机场考试的内容主要包括理论和实飞两部分。 理论考试主要涵盖无人机相关的知识&#xff0c;包括无人机的原理、结构、操作规范等。 实飞考试则主要考察飞行技能&#xff0c;包括飞行操作、航线规划、飞行稳定性等。 具体来说&#xff0c;实飞部分可能包括使用GPS…

前端渲染页面的原理

之前一直不愿意写一篇关于原理的&#xff0c;因为说起来实在是太繁杂&#xff0c;要写得细&#xff0c;码字梳理&#xff0c;计算下来起码都要差不多三周。以前一直躲避这个事情&#xff0c;现在反正有时间&#xff0c;为了不荒废自己&#xff0c;那就从头捋一遍。也方便自己后…

【STL库源码剖析】list 简单实现

从此音尘各悄然 春山如黛草如烟 目录 list 的结点设计 list 的迭代器 list 的部分框架 迭代器的实现 容量相关相关函数 实现 insert 在指定位置插入 val 实现 push_back 在尾部进行插入 实现 erase 在指定位置删除 实现 pop_back 在尾部进行删除 实现 list 的头插、头删 实现…

循环buffer“一写多读“

1.往期回顾 一个简单实用的循环buffer&#xff0c;用于缓冲数据&#xff01;测试500M数据&#xff0c;耗时1.3秒。 C语言版本的循环buffer比C版本的速度更快&#xff01;测试500M数据0.5秒&#xff0c;达9.25Gbps左右&#xff01; C 语言免拷贝版本循环 buffer 比拷贝版本快了…

熵值法(熵权法)

熵值法&#xff08;Entropy Method&#xff09;是一种多属性决策分析方法&#xff0c;主要用于权重确定、排序和评价。它在风险评估、资源配置、环境管理等领域得到广泛应用。熵值法的核心思想是基于信息熵的概念&#xff0c;利用信息熵来度量各属性对决策的贡献程度&#xff0…

农产品产品防伪防窜货+二维码防伪+溯源系统源码全平台一物一码数字化防伪防窜货和溯源查询系统

农产品产品防伪防防窜货二维码防伪溯源系统源码全平台一物一码数字化防伪防窜货和溯源查询系统 产品防伪防防窜货二维码防伪溯源系统源码&#xff0c;该系统采用最简单易用的phpMySQL进行搭建&#xff0c;拥有完善的网站前后台&#xff0c;通过对每件产品生产线上的单品、二级…

BIGO前端CICD平台

本文首发于&#xff1a;https://github.com/bigo-frontend/blog/ 欢迎关注、转载。 我是谁 BIGO前端CICD平台&#xff0c;是一个服务于前端团队的全研发周期管理平台&#xff0c;已经是我们团队日常都要使用的工具了。 该平台实现了一键创建项目、发布编排、新建迭代、checkl…

【微服务】部署mysql集群,主从复制,读写分离

两台服务器做如下操作 1.安装mysqldocker pull mysql:5.72.启动以及数据挂载 mkdir /root/mysql/data /root/mysql/log /root/mysql/conf touch my.conf //mysql的配置文件docker run --name mysql \ -e MYSQL_ROOT_PASSWORD123456 \ -v /root/mysql/data:/var/lib/mysql \ -v…

如何创建一个vue项目?详细教程,如何创建第一个vue项目?

已经安装node.js在自己找的到的地方新建一个文件夹用于存放项目&#xff0c;记住文件夹的存放路径&#xff0c;以我为例&#xff0c;我的文件夹路径为D:\tydic 打开cmd命令窗口&#xff0c;进入刚刚的新建文件夹 切换硬盘&#xff1a; D: 进入文件夹&#xff1a;cd tydic 使…

基于ViutualBox+Ubuntu(Linux)的开发环境搭建

实际在选择虚拟机的时候纠结了要用virualbox还是vmware&#xff0c;初步比较结果&#xff1a; 1.virualbox能够使用vmware的硬盘格式&#xff0c;因此可以自由选择。 2.都能够实现主机和宿主机之间的文件夹共享。 3.virualbox是自由软件&#xff0c;vmware是商业软件。 在功能上…