dynamic-datasource 多数据源
注:dynamic-datasource 不支持 JPA
1.项目结构
framework-dynamic-datasource
└─src
└─main
├─java
│ └─com
│ └─yan
│ ├─abstractinterface
│ │ └─config
│ │ └─dynamic
│ │ └─Impl
│ └─config
│ └─dynamic
└─resources
2.com.yan.abstractinterface.config.dynamic
2.1 AbstractDynamicDataSource
DynamicDataSource 抽象接口可通过实现该接口 的 getDataSourceName() 指定数据源名称
已支持shardingjdbc原生的配置方式
package com.yan.abstractinterface.config.dynamic;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.util.Map;
import java.util.logging.Logger;
/**
* @Author yan
* @Date 2024/10/25 上午8:05:07
* @Description
*/
public interface AbstractDynamicDataSource {
/**
* 默认分表数据源名称
*/
String SHARDING_DATA_SOURCE_NAME = "sharding";
/**
* 分表数据源名称 重写修改数据源名称
*
* @return
*/
default String getDataSourceName() {
return SHARDING_DATA_SOURCE_NAME;
}
/**
* 将动态数据源设置为首选的
* 当spring存在多个数据源时, 自动注入的是首选的对象
* 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
*
* @return
*/
default DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) throws Exception {
DynamicDataSourceProperties dynamicDataSourceProperties = getDynamicDataSourceProperties();
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());
dataSource.setStrict(dynamicDataSourceProperties.getStrict());
dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());
dataSource.setProvider(dynamicDataSourceProvider);
dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());
dataSource.setSeata(dynamicDataSourceProperties.getSeata());
return dataSource;
}
default DataSource dataSource() throws Exception {
DynamicDataSourceProvider dynamicDataSourceProvider = SpringUtil.getBean(DynamicDataSourceProvider.class);
if (dynamicDataSourceProvider == null) {
throw new Exception(" 分库分表数据源未配置 ");
}
return dataSource(dynamicDataSourceProvider);
}
/**
* 动态 数据源配置
* 将shardingDataSource放到了多数据源(dataSourceMap)中
* 注意有个版本的bug,3.1.1版本 不会进入loadDataSources 方法,这样就一直造成数据源注册失败
*/
default DynamicDataSourceProvider dynamicDataSourceProvider() throws Exception {
Map<String, DataSourceProperty> datasourceMap = getDynamicDataSourceProperties().getDatasource();
return new AbstractDataSourceProvider() {
@Override
public Map<String, DataSource> loadDataSources() {
Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);
// 将 shardingjdbc 管理的数据源也交给动态数据源管理
try {
org.slf4j.Logger logger = LoggerFactory.getLogger(getClass().getName());
String dataSourceName = getDataSourceName();
DataSource dataSource = getDataSource();
if (ObjectUtil.isNotEmpty(dataSource) && ObjectUtil.isNotEmpty(dataSourceName)) {
logger.info("dataSourceName : {}", dataSourceName);
dataSourceMap.put(dataSourceName, dataSource);
logger.info("DataSource init success");
} else {
logger.warn("DataSource init error :name can not null and DataSource can not null");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
Map<String, DataSource> extendedDataSource = getExtendedDataSource();
if (CollUtil.isNotEmpty(extendedDataSource)) {
dataSourceMap.putAll(extendedDataSource);
}
return dataSourceMap;
}
};
}
/**
* 扩展数据源
*
* @return
*/
default Map<String, DataSource> getExtendedDataSource() {
return null;
}
/**
* 分库分表数据源
*
* @return
* @throws Exception
*/
default DataSource getDataSource() throws Exception {
return SpringUtil.getBean(DataSource.class);
}
default DynamicDataSourceProperties getDynamicDataSourceProperties() throws Exception {
DynamicDataSourceProperties dynamicDataSourceProperties = SpringUtil.getBean(DynamicDataSourceProperties.class);
if (dynamicDataSourceProperties == null) {
throw new Exception(" 多数据源未配置 ");
}
return dynamicDataSourceProperties;
}
}
2.2 DefaultDynamicDataSourceImpl
默认实现方式 DefaultDynamicDataSourceImpl 使用 @Service @Primary 注解覆盖 DefaultDynamicDataSourceImpl
package com.yan.abstractinterface.config.dynamic.Impl;
import com.yan.abstractinterface.config.dynamic.AbstractDynamicDataSource;
import org.springframework.stereotype.Service;
/**
* @Author yan
* @Date 2024/10/25 上午9:00:36
* @Description
*/
@Service
public class DefaultDynamicDataSourceImpl implements AbstractDynamicDataSource {
}
3.com.yan.config.dynamic
3.1 DynamicDataSourceConfig
实际配置注入
package com.yan.config.dynamic;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.yan.abstractinterface.config.dynamic.AbstractDynamicDataSource;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
* @Author yan
* @Date 2024/7/3 0003 15:59:02
* @Description 不使用该配置类,使用以下注释在启动类上排除
* @ComponentScan(excludeFilters = {
* @ComponentScan.Filter(type = FilterType.REGEX,pattern = "com.yan.config.dynamic.DynamicDataSourceConfig")
* })
*/
@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class DynamicDataSourceConfig {
private AbstractDynamicDataSource getAbstractDynamicDataSource() {
return SpringUtil.getBean(AbstractDynamicDataSource.class);
}
public DataSource getDataSource() throws Exception {
return getAbstractDynamicDataSource().getDataSource();
}
/**
* 将shardingDataSource放到了多数据源(dataSourceMap)中
* 注意有个版本的bug,3.1.1版本 不会进入loadDataSources 方法,这样就一直造成数据源注册失败
*/
@Bean
public DynamicDataSourceProvider initDynamicDataSourceProvider() throws Exception {
return getAbstractDynamicDataSource().dynamicDataSourceProvider();
}
/**
* 将动态数据源设置为首选的
* 当spring存在多个数据源时, 自动注入的是首选的对象
* 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
* 以下二选一为bean Primary
*
* @return
*/
@Primary
@Bean
public DataSource initDataSource() throws Exception {
return getAbstractDynamicDataSource().dataSource();
}
//initDataSource()重复 选1个即可
//@Primary
//@Bean
public DataSource initDataSource(DynamicDataSourceProvider dynamicDataSourceProvider) throws Exception {
return getAbstractDynamicDataSource().dataSource(dynamicDataSourceProvider);
}
}
4.依赖
<dependency>
<groupId>com.yan</groupId>
<artifactId>framework-dynamic-datasource</artifactId>
<version>${project-module.version}</version>
</dependency>