🎨领域:Java后端开发
🔥收录专栏: 框架
🐒个人主页:BreezAm
💖Gitee:https://gitee.com/BreezAm
✨个人标签:【后端】【大数据】【前端】【运维】
文章目录
介绍
有的时候,有这样的一个场景,就是要在项目运行的过程中动态修改数据源的配置信息,而且要在不重启项目的情况下进行,本文以多数据源为例进行讲解,相关测试环境如下:
- 数据库:MySQL
- 多数据:dynamic-datasource
- 连接池:spring boot自带的连接池
- 配置中心: nacos 2.0.3
- 持久层:mybatis plus 3.5.1
- spring cloud:2021.0.5
- spring cloud alibaba:2021.0.4.0
- springboot:2.7.7
一、相关依赖
这里只给出比较核心的依赖,其他的依赖就不给出了,例如jdbc啥的。
1.1 nacos客户端
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.0.3</version>
</dependency>
1.1 配置中心
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
1.3 动态数据源
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.1</version>
</dependency>
1.4 mybatis plus
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
二、实战
2.1 配置文件
需要在nacos上面建立相应的配置文件。
spring:
application:
name: smile-mybatisplus
profiles:
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 192.168.0.100:8848
config:
# 配置中心地址
server-addr: 192.168.0.100:8848
# 配置文件格式
file-extension: yml
refresh-enabled: true
# 共享配置
shared-configs:
- data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
refresh: true
2.2 新建一个配置属性类
DynamicDataSourceProperties 是动态数据源的配置类,因为我们需要让其动态刷新,因此需要进行重写。其实(我也挺疑惑的,这些配置不是nacos会自动刷新的吗,但是我试过了,不行,所以只能自己建一个类)。
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
public class MyDynamicDataSourceProperties extends DynamicDataSourceProperties {
}
2.3 配置属性动态刷新
这里主要做的是加入注解@RefreshScope,他会为当前注册的bean生成一个代理对象,每次接受到刷新事件,都会重新生成一个放入容器,以前那个会被销毁掉。
@RefreshScope
@Configuration(proxyBeanMethods = false)
public class DynamicPropertiesConfig {
@RefreshScope
@Bean("dynamicDataSourceProperties")
@Primary
@ConditionalOnMissingBean
public DynamicDataSourceProperties dynamicDataSourceProperties() {
return new MyDynamicDataSourceProperties();
}
}
2.4 重写多数据源自动配置
我们要让dataSource这个bean动态修改,那么就需要让这个bean的生成是动态的,通过查看源码可知,这个bean是支持重写的(方法上面有注解@ConditionalOnMissingBean),感兴趣的读者可以去多数据源自动配置类DynamicDataSourceAutoConfiguration
,因此把数据源生成的地方进行重写,加上注解@RefreshScope
,这样就可以支持动态刷新了,刷新的逻辑是,当nacos配置发生改变的时候,会发布一个事件,而加上这个注解后相当于是一个监听器。
@RefreshScope
@DependsOn("dynamicDataSourceProperties")
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
@Configuration(proxyBeanMethods = false)
public class DynamicDataSourceConfig {
@Autowired
private DynamicDataSourceProperties properties;
@Bean
@RefreshScope
@ConditionalOnMissingBean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
return new YmlDynamicDataSourceProvider(datasourceMap);
}
@RefreshScope
@ConditionalOnMissingBean
public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setProvider(dynamicDataSourceProvider);
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
}
三、源码介绍
其实动态刷新的结果还得归功于@RefreshScope
和@Scope("refresh")
注解,底层是通过发布订阅设计模式实现的,会有事件发布者和监听者。
感兴趣的读者可以去阅读以下几个类:
-
ConfigurationPropertiesRebinder
-
ConfigurationPropertiesBeans
-
RefreshScope
-
RefreshScopeRefreshedEvent
-
…
🔥收录专栏:框架