⼀⽂读懂Spring动态配置多数据源---源码详细分析
Spring动态多数据源源码分析及解读
⼀、为什么要研究Spring动态多数据源
期初,最开始的原因是:想将答题服务中发送主观题答题数据给批改中间件这块抽象出来,但这块主要使⽤的是mq消息的⽅式发送到批改中间件,所以,最后决定将mq 进⾏抽象,抽象后的结果是:语⽂,英语,通⽤任务都能个性化的配置mq,且可以扩展到任何使⽤mq的业务场景上。终端需要做的就是增加mq配置,⾃定义消费者业务逻辑⽅法,调⽤send⽅法即可。
这样做的好处是:原本在每个使⽤到mq的项⽬⾥都要写⼀遍mq⽣产者,mq消费者,发送mq数据,监听mq消费等动作,且如果⼀个项⽬⾥有多个mq配置,要写多遍这样的配置。抽象后,只需要配置⽂件中进⾏配置,然后⾃定义个性化的业务逻辑消费者,就可以进⾏mq发送了。
这样⼀个可动态配置的mq,要求还是挺多的,如何动态配置? 如何能够在服务器启动的时候就启动n个mq的⽣产者和消费者?发送数据的时候, 怎么到正确的mq发送呢?
其实, 我⼀直相信, 我遇到的问题, 肯定有⼤神已经遇到过, 并且已经有了成熟的解决⽅案了. 于是, 开始搜索⾏业内的解决⽅案, 了很久也没到,最后在同事的提⽰下,发现Spring动态配置多数据源的思想和
我想实现的动态配置多MQ的思想类似。于是,我开始花时间研究Spring动态多数据源的源码。
⼆、Spring动态多数据源框架梳理
2.1 框架结构
Spring动态多数据源是⼀个我们在项⽬中常⽤到的组件,尤其是做项⽬重构,有多种数据库,不同的请求可能会调⽤不同的数据源。这时,就需要动态调⽤指定的数据源。我们来看看Spring动态多数据源的整体框架
上图中虚线框部分是Spring动态多数据源的⼏个组成部分
1. ds处理器
2. aop切⾯
3. 创建数据源
4. 动态数据源提供者
5. 动态连接数据库
除此之外,还可以看到如下信息:
1. Spring动态多数据源是通过动态配置配置⽂件的⽅式来指定多数据源的。
2. Spring动态多数据源⽀持四种类型的数据:base数据源,jndi数据源,druid数据源,hikari数据源。
3. 多种触发机制:通过header配置ds,通过session配置ds,通过spel配置ds,其中ds是datasource的简称。
4. ⽀持数据源嵌套:⼀个请求过来,这个请求可能会访问多个数据源,也就是⽅法嵌套的时候调⽤多数据源,也是⽀持的。
2.2 源码结构
Spring动态多数据源的⼏个组成部分,在代码源码结构中完美的体现出来。
上图是Spring动态多数据源的源码项⽬结构,我们主要列⼀下主要的结构----annotation:定义了DS主机
----aop:定义了⼀个前置通知,切⾯类
----creator:动态多数据源的创建器
----exception:异常处理
----matcher:匹配器
----processor:ds处理器
----provider:数据员提供者
----spring:spring动态多数据源启动配置相关类
----toolkit:⼯具包
----AbstractRoutingDataSource:动态路由数据源抽象类
----DynamicRoutingDataSource:动态路由数据源实现类
2.3 整体项⽬结构图
下图是Spring多态多数据源的代码项⽬结构图。
这个图内容⽐较多,所以字⽐较⼩,⼤概看出⼀共有6个部分就可以了。后⾯会就每⼀个部分详细说明。
三、项⽬源码分析
3.1 引⼊Spring依赖jar包.
Spring动态多数据源,我们在使⽤的时候,直接引⼊jar,然后配置数据源就可以使⽤了。配置jar包如下
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
然后是在yml配置⽂件中增加配置
# master
spring.datasource.dynamic.datasource.master.sql.jdbc.Driver
spring.datasource.dynamic.datasource.master.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8
spring.datasource.dynamic.datasource.master.username=root
spring.datasource.dynamic.datasource.master.password=123456
# slave
spring.datasource.dynamic.datasource.slave.sql.jdbc.Driver
spring.datasource.dynamic.datasource.slave.url=jdbc:mysql://localhost:3306/test1?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8
spring.datasource.dynamic.datasource.slave.username=root
spring.datasource.dynamic.datasource.slave.password=123456
在测试的时候,使⽤了两个不同的数据库,⼀个是test,⼀个是test1
3.2 Spring 源码分析的⼊⼝
为什么引⼊jar就能在项⽬⾥使⽤了呢?因为在jar包⾥配置了META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration
在这个⽂件⾥,指定了spring动态加载的时候要⾃动扫描的⽂件DynamicDataSourceAutoConfiguration,这个⽂件就是源码项⽬的⼊⼝了。这⾥定义了项⽬启动⾃动装备DynamicDataSourceAutoConfiguration⽂件。
接下来,我们就来看看DynamicDataSourceAutoConfiguration⽂件。
3.3、Spring配置⽂件⼊⼝。
下图是DynamicDataSourceAutoConfiguration⽂件的主要内容。
Spring配置⽂件主要的作⽤是在系统加载的时候,就加载相关的bean。这⾥项⽬初始化的时候都加载了哪些bean呢?
1. 动态数据源属性类DynamicDataSourceProperties
2. 数据源处理器DsProcessor,采⽤责任链设计模式3种⽅法加载ds
3. 动态数据源注解类DynamicDataSourceAnnotationAdvisor,包括前置通知,切⾯类,切点的加载
4. 数据源创建器DataSourceCreator,这个⽅法是在另⼀个类被加载的DynamicDataSourceCreatorAutoConfiguration。也是⾃动配置bean类。可以选择4种类型的数据
源进⾏创建。
5. 数据源提供者Provider,这是动态初始化数据源,读取yml配置⽂件,在配置⽂件中可配置1个或多个数据源。
接下来看⼀下源代码
1. DynamicDataSourceAutoConfiguration动态数据源配置⽂件
@Slf4j
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@Import(value = {DruidDynamicDataSourceConfiguration.class, DynamicDataSourceCreatorAutoConfiguration.class})
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class DynamicDataSourceAutoConfiguration {
private final DynamicDataSourceProperties properties;
@Bean
@ConditionalOnMissingBean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
Map<String, DataSourceProperty> datasourceMap = Datasource();
return new YmlDynamicDataSourceProvider(datasourceMap);
}
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.Primary());
dataSource.Strict());
dataSource.Strategy());
dataSource.setProvider(dynamicDataSourceProvider);
dataSource.P6spy());
dataSource.Seata());
return dataSource;
}
@Bean
@ConditionalOnMissingBean
public DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {
DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor();
interceptor.setDsProcessor(dsProcessor);
DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);
advisor.Order());
return advisor;
}
@Bean
@ConditionalOnMissingBean
public DsProcessor dsProcessor() {
DsHeaderProcessor headerProcessor = new DsHeaderProcessor();
DsSessionProcessor sessionProcessor = new DsSessionProcessor();
DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();
headerProcessor.setNextProcessor(sessionProcessor);
sessionProcessor.setNextProcessor(spelExpressionProcessor);
return headerProcessor;
}
@Bean
@ConditionalOnBean(DynamicDataSourceConfigure.class)
public DynamicDataSourceAdvisor dynamicAdvisor(DynamicDataSourceConfigure dynamicDataSourceConfigure, DsProcessor dsProcessor) {
DynamicDataSourceAdvisor advisor = new Matchers());
advisor.setDsProcessor(dsProcessor);
advisor.setOrder(Ordered.HIGHEST_PRECEDENCE);
return advisor;
}
}
看到这段代码,我们就⽐较熟悉了,这就是通过注解的⽅式,在项⽬启动的时候,⾃动注⼊bean。我们来详细看⼀下,他都注⼊了哪些内容。
1. 动态多数据源预置处理器dsProcess,ds就是datasource的简称。这⾥主要采⽤的是责任链设计模式,获取ds。
2. 动态多数据源注解通知dynamicDatasourceAnnotationAdvisor,这是⼀个aop前置通知,当⼀个请求发⽣的时候,会触发前置通知,⽤来确定到底使⽤哪⼀个mq消息
队列
3. 动态多数据源提供者dynamicDataSourceProvider,我们是动态配置多个数据源,那么就有⼀个解析配置的过程,解析配置就是在这⾥完成的,解析出多个数据源,
然后分别调⽤数据源创建者去创建数据源。Spring动态多数据源⽀持数据源的嵌套。
4. 动态路由到数据源DynamicRoutingDataSource,当请求过来的时候,也到对应的数据源了,要建⽴数据库连接,数据库连接的操作就是在这⾥完成的。
我们发现在这⾥就有四个bean的初始化,并没有bean的create创建过程,bean的创建过程是在另⼀个配置类(DynamicDataSourceCreatorAutoConfiguration)中完成的。
@Slf4j
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
public class DynamicDataSourceCreatorAutoConfiguration {
private final DynamicDataSourceProperties properties;
@Bean
@ConditionalOnMissingBean
public DataSourceCreator dataSourceCreator() {
DataSourceCreator dataSourceCreator = new DataSourceCreator();
dataSourceCreator.setBasicDataSourceCreator(basicDataSourceCreator());
dataSourceCreator.setJndiDataSourceCreator(jndiDataSourceCreator());
dataSourceCreator.setDruidDataSourceCreator(druidDataSourceCreator());
dataSourceCreator.setHikariDataSourceCreator(hikariDataSourceCreator());
dataSourceCreator.PublicKey());
return dataSourceCreator;
}
@Bean
mysql下载jar包@ConditionalOnMissingBean
public BasicDataSourceCreator basicDataSourceCreator() {
return new BasicDataSourceCreator();
}
@Bean
@ConditionalOnMissingBean
public JndiDataSourceCreator jndiDataSourceCreator() {
return new JndiDataSourceCreator();
}
@Bean
@ConditionalOnMissingBean
public DruidDataSourceCreator druidDataSourceCreator() {
return new Druid());
}
@Bean
@ConditionalOnMissingBean
public HikariDataSourceCreator hikariDataSourceCreator() {
return new Hikari());
}
}
⼤概是因为考虑到数据的种类⽐较多,所以将其单独放到了⼀个配置⾥⾯。从上⾯的源码可以看出,有四种类型的数据源配置。分别是:basic、jndi、druid、hikari。这四种数据源通过组合设计模式被set到DataSourceCreator中。
接下来,分别来看每⼀个模块都做了哪些事情。
四、通过责任链设计模式获取数据源名称
Spring动态多数据源,获取数据源名称的⽅式有3种,这3中⽅式采⽤的是责任链⽅式连续获取的。⾸先在header中获取,header中没有,去session中获取, session中也没有,通过spel获取。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论