Spring Boot 多数据源解决方案:dynamic-datasource-spring-boot-starter 的奥秘(上)

embedded/2025/3/11 8:57:12/

在 Spring Boot 生态中,dynamic-datasource-spring-boot-starter 是一个非常实用的组件,它为我们在多数据源场景下提供了便捷的解决方案。在上一篇文章《一分钟上手:如何创建你的第一个 Spring Boot Starter》中,我们学习了如何创建自己的 starter,今天我们就来深入探究下 dynamic-datasource-spring-boot-starter 的源码,了解它是如何实现动态数据源切换功能的。

一、dynamic-datasource-spring-boot-starter介绍

dynamic-datasource-spring-boot-starter 是一个用于在 Spring Boot 项目中实现动态数据源切换的工具

在实际的应用开发中,经常会遇到需要连接多个数据源的情况,例如一个销售系统会根据不同的业务模块,如线索、订单、库存、物流等连接到不同的数据库。手动管理多个数据源的切换和配置是一项复杂且容易出错的任务,而这个 starter 就是为了解决这些问题而生。

二、依赖的jar包

1. SpringBoot相关依赖

提供了JDBC数据库连接操作、AOP(面向切面编程)、Actuator应用监控、Web应用开发等功能,Actuator和Web依赖都是可选的,不是必须的

	<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><optional>true</optional></dependency>

2. MyBatis-Plus

增强版的MyBatis框架,可以极大简化数据库操作,业务的mapper层只需要继承BaseMapper,即可使用mybatis-plus提供的增删改查的API。使开发者能够更加专注于业务逻辑的实现,而无需在复杂的 SQL 编写和数据库连接管理上耗费过多精力。该jar包也是可选的,不是必须的

3. 连接池

HikariCP、Druid、Beecp、Commons DBCP2等用于管理数据库连接。
这些jar包也都是可选的后端开发使用的最多的还是Druid数据库连接池

	<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP-java7</artifactId><version>${hikariCp.version}</version><optional>true</optional></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version><optional>true</optional></dependency><dependency><groupId>com.github.chris2018998</groupId><artifactId>beecp</artifactId><version>${beeCp.version}</version><optional>true</optional></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-dbcp2</artifactId><version>${dbcp2.version}</version><optional>true</optional></dependency>

4. 配置处理器

在开发阶段为 IDE 提供辅助功能,如代码提示和验证配置属性的正确性。在项目的实际运行时,并不需要这个依赖来执行应用程序的核心逻辑,所以也将其设置为可选,避免了不必要的依赖传递,减小了项目最终打包的体积

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency>

5. P6Spy

用于监控和调试SQL语句。可能在开发和测试环境中非常有用,但在生产环境中可能不需要,所以业将其标记为可选依赖,让使用方根据实际情况决定是否引入。

6. Seata

提供分布式事务解决方案,根据项目实际需要决定要不要引入,所以该jar包也是可选的。

三、DynamicDataSourceAutoConfiguration类剖析

DynamicDataSourceAutoConfiguration类是dynamic-datasource-spring-boot-starter包的自动配置类,整个动态数据源的配置和初始化都在这里。

@Configuration
@EnableConfigurationProperties({DynamicDataSourceProperties.class})
@AutoConfigureBefore(value = {DataSourceAutoConfiguration.class},name = {"com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure"}
)
@Import({DruidDynamicDataSourceConfiguration.class, DynamicDataSourceCreatorAutoConfiguration.class, DynamicDataSourceHealthCheckConfiguration.class})
@ConditionalOnProperty(prefix = "spring.datasource.dynamic",name = {"enabled"},havingValue = "true",matchIfMissing = true
)
public class DynamicDataSourceAutoConfiguration {……
}

这种配置类相关的注解之前的博客也分享过,这里就不再赘述了,我们重点来剖析下该配置类中的几个关键方法。

1. dynamicDataSourceProvider方法

用于创建动态数据源提供者 DynamicDataSourceProvider。其主要职责是根据配置文件中的数据源信息构建数据源对象,并将其提供给动态数据源路由机制。

	@Bean@ConditionalOnMissingBean // 确保Spring容器中不存在 DynamicDataSourceProvider 类型的 Bean 时才创建该 Beanpublic DynamicDataSourceProvider dynamicDataSourceProvider() {Map<String, DataSourceProperty> datasourceMap = this.properties.getDatasource();return new YmlDynamicDataSourceProvider(datasourceMap);}

2. dataSource方法

用于是创建动态数据源 DynamicRoutingDataSource。它整合了各种配置信息,包括默认数据源、严格模式、切换策略、数据源提供者以及与SQL语句监控和分布式事务相关的配置,构建出一个完整的动态数据源对象,使其能够在运行时根据不同条件动态切换数据源。

	@Bean@ConditionalOnMissingBeanpublic DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();// 默认数据源dataSource.setPrimary(this.properties.getPrimary());// 根据配置决定在数据源切换时是否进行严格检查,以确保数据源的正确性和一致性。dataSource.setStrict(this.properties.getStrict());// 数据源切换策略,如基于注解、基于配置文件或基于特定规则的切换策略dataSource.setStrategy(this.properties.getStrategy());dataSource.setProvider(dynamicDataSourceProvider);dataSource.setP6spy(this.properties.getP6spy());dataSource.setSeata(this.properties.getSeata());return dataSource;}

3. dynamicDatasourceAnnotationAdvisor 方法

负责创建动态数据源注解切面的Advisor。用于在方法执行时根据注解信息进行数据源切换。

	@Role(2)@Beanpublic Advisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor(this.properties.isAllowedPublicOnly(), dsProcessor);DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);advisor.setOrder(this.properties.getOrder());return advisor;}

4. dynamicTransactionAdvisor 方法

用于创建动态事务 Advisor。它定义了一个基于注解的事务切面,用于在方法执行时管理事务,确保数据库操作的原子性、一致性、隔离性和持久性。

	@Role(2)@ConditionalOnProperty(prefix = "spring.datasource.dynamic",name = {"seata"},havingValue = "false",matchIfMissing = true)@Beanpublic Advisor dynamicTransactionAdvisor() {AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();pointcut.setExpression("@annotation(com.baomidou.dynamic.datasource.annotation.DSTransactional)");return new DefaultPointcutAdvisor(pointcut, new DynamicLocalTransactionAdvisor());}

5. dsProcessor 方法

用于创建数据源处理器 DsProcessor。数据源处理器负责根据不同的条件(如请求头、会话信息、SpEL 表达式等)确定要切换的数据源,是实现动态数据源切换逻辑的关键组件之一。

自动配置类剖析完了,剩下的就是配置属性类DynamicDataSourceProperties和spring.factories 文件了。

@ConfigurationProperties(prefix = "spring.datasource.dynamic"
)
public class DynamicDataSourceProperties {private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceProperties.class);public static final String PREFIX = "spring.datasource.dynamic";public static final String HEALTH = "spring.datasource.dynamic.health";public static final String DEFAULT_VALID_QUERY = "SELECT 1";private String primary = "master";private Boolean strict = false;private Boolean p6spy = false;private Boolean seata = false;private Boolean lazy = false;private SeataMode seataMode;private boolean health;private String healthValidQuery;private Map<String, DataSourceProperty> datasource;private Class<? extends DynamicDataSourceStrategy> strategy;private Integer order;@NestedConfigurationPropertyprivate DruidConfig druid;@NestedConfigurationPropertyprivate HikariCpConfig hikari;@NestedConfigurationPropertyprivate BeeCpConfig beecp;@NestedConfigurationPropertyprivate Dbcp2Config dbcp2;private String publicKey;private boolean allowedPublicOnly;……
}

DynamicDataSourceProperties一般都配置在Apollo中。

以下是spring.factories文件。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=

com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration

四、总结

通过对 dynamic-datasource-spring-boot-starter 的剖析,我们可以了解到它是实现动态数据源切换的机制。这一组件为开发者在处理多数据源场景时提供了极大的便利,使得应用的可扩展性和可维护性得到了显著提升。


http://www.ppmy.cn/embedded/171719.html

相关文章

deepseek的regflow安装mac版本

deepseek的ragflow部署安装 一:ollama安装,自行完成,我本地已安装 二:查看大模型情况oll::命令ollama list,我本地无ragflow 三:docker安装:命令docker version ,自行完成,我本地已安装 四:安装知识库软件ragflow: 简单科普下Ragflow 是一个基于深度学习模型的问答生成工具&…

WPS条件格式:B列的值大于800,并且E列的值大于B列乘以0.4时,这一行的背景标红

一、选择数据区域 选中需要应用条件格式的区域&#xff08;例如A2:E100 &#xff09;。 二、打开条件格式 点击“开始”选项卡&#xff0c;选择“条件格式” > “新建规则”。 三、选择规则类型 选择“使用公式确定要设置格式的单元格”。 四、输入公式 在公式框中输入以…

远程监控项目描述以及总体框架

远程监控项目基于之前的本地渲染项目做了一个扩展。本地渲染项目没有涉及到解码部分&#xff0c;是直接从rv126拿到摄像头的vi数据&#xff0c;做转换就刷新到了上面去。 uvc摄像头用ffmpeg做推流&#xff0c;所以这个远程是先拿到我们这个uvc摄像头的数据进行解码才能刷新到网…

React之userEffect的使用

一、userEffect是什么 在React组件中&#xff0c;副作用操作是指那些会被影响的其他的组件&#xff0c;而且不能在渲染过程中完成相关操作。其中&#xff0c;常见的副作用就是从API接口中获取数据。而 useEffect 提供了一种在函数组件中处理副作用的方式&#xff0c;使得函数组…

工业数据采集与控制:ARM一体机的低功耗高可靠性方案

在工业4.0和智能化转型的浪潮下&#xff0c;传统工业现场的数据采集与控制方式正在被颠覆。过去&#xff0c;工业现场的数据采集和控制往往依赖于分散的设备和复杂的系统集成&#xff0c;而如今&#xff0c;ARM工业现场采集控制看板显示一体机的出现&#xff0c;为工业自动化带…

2线性表之链表

1.链表 链表是一种 物理存储结构上非连续、非顺序 的存储结构&#xff0c;数据元素的 逻辑顺序 是通过链表中的 指针链接 次序实现的 。 关于顺序表的不足&#xff1a; 扩容有性能消耗且有可能存在空间浪费。 扩容时&#xff0c;如果扩小了&#xff0c;大量插入数据时&#xff…

Python大数据可视化:基于大数据技术的共享单车数据分析与辅助管理系统_flask+hadoop+spider

开发语言&#xff1a;Python框架&#xff1a;flaskPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 场地信息界面 单车信息界面 归还信息界面 共享单车界面 系…

Unity 通用UI界面逻辑总结

概述 在游戏开发中&#xff0c;常常会遇到一些通用的界面逻辑&#xff0c;它不论在什么类型的游戏中都会出现。为了避免重复造轮子&#xff0c;本文总结并提供了一些常用UI界面的实现逻辑。希望可以帮助大家快速开发通用界面模块&#xff0c;也可以在次基础上进行扩展修改&…