mirror of
https://gitee.com/wangkang/udf.git
synced 2026-11-03 17:03:41 +00:00
添加动态数据源
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
<module>udf-starter-connection-pool-druid</module>
|
||||
<module>udf-starter-qrcode</module>
|
||||
<module>udf-starter-auth</module>
|
||||
<module>udf-starter-datasource-dynamic</module>
|
||||
</modules>
|
||||
<!-- 依赖管理 -->
|
||||
<dependencyManagement>
|
||||
@@ -121,6 +122,12 @@
|
||||
<artifactId>udf-starter-datasource</artifactId>
|
||||
<version>${udf-starter.version}</version>
|
||||
</dependency>
|
||||
<!-- udf-starter-datasource-dynamic -->
|
||||
<dependency>
|
||||
<groupId>org.itkk.udf</groupId>
|
||||
<artifactId>udf-starter-datasource-dynamic</artifactId>
|
||||
<version>${udf-starter.version}</version>
|
||||
</dependency>
|
||||
<!-- udf-starter-connection-pool-druid -->
|
||||
<dependency>
|
||||
<groupId>org.itkk.udf</groupId>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="true">
|
||||
<fileset name="all" enabled="true" check-config-name="itkk.org" local="false">
|
||||
<file-match-pattern match-pattern="." include-pattern="true"/>
|
||||
</fileset>
|
||||
</fileset-config>
|
||||
@@ -0,0 +1,4 @@
|
||||
/target/
|
||||
/bin/
|
||||
/.classpath
|
||||
/.project
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- maven坐标 -->
|
||||
<artifactId>udf-starter-datasource-dynamic</artifactId>
|
||||
<name>udf-starter-datasource-dynamic</name>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://itkk.org:81</url>
|
||||
<!-- 父依赖 -->
|
||||
<parent>
|
||||
<groupId>org.itkk.udf</groupId>
|
||||
<artifactId>udf-starter</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.itkk.udf</groupId>
|
||||
<artifactId>udf-starter-core</artifactId>
|
||||
</dependency>
|
||||
<!-- spring-boot-starter-jdbc -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package org.itkk.udf.datasource.dynamic;
|
||||
|
||||
/**
|
||||
* 描述 : 数据源本地线程
|
||||
*
|
||||
* @author wangkang
|
||||
*/
|
||||
public class DataSourceThreadLocal extends ThreadLocal<String> {
|
||||
/*
|
||||
* 修改点参考:http://blog.csdn.net/cxh5060/article/details/49275633
|
||||
* @see java.lang.ThreadLocal#remove()
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
this.initialValue();
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package org.itkk.udf.datasource.dynamic;
|
||||
|
||||
/**
|
||||
* 描述 : DbContextHolder
|
||||
* <p/>
|
||||
* 多个登入用户可能需要同时切换数据源,所以这里需要写一个线程安全的ThreadLocal 用户切换数据源只要在线程中使用
|
||||
*
|
||||
* @author wangkang
|
||||
*/
|
||||
public class DbContextHolder {
|
||||
|
||||
/**
|
||||
* 描述 : 本地线程
|
||||
*/
|
||||
private static final ThreadLocal<String> CONTEXTHOLDER = new DataSourceThreadLocal();
|
||||
|
||||
/**
|
||||
* 描述 : 私有构造函数
|
||||
*/
|
||||
private DbContextHolder() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述 : 设置数据源代码
|
||||
*
|
||||
* @param code 数据源代码
|
||||
*/
|
||||
public static void setDataSourceCode(String code) {
|
||||
CONTEXTHOLDER.set(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 描述 : 获取数据源代码
|
||||
*
|
||||
* @return 数据源代码
|
||||
*/
|
||||
public static String getDataSourceCode() {
|
||||
return CONTEXTHOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Description: 清理数据源代码
|
||||
* </p>
|
||||
*/
|
||||
public static void clearDataSourceCode() {
|
||||
CONTEXTHOLDER.remove();
|
||||
}
|
||||
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package org.itkk.udf.datasource.dynamic;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.itkk.udf.core.domain.datasource.DataSourceMeta;
|
||||
import org.itkk.udf.core.domain.datasource.IBuildDataSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 描述 : DynamicDataSource
|
||||
*
|
||||
* @author wangkang
|
||||
*/
|
||||
@Slf4j
|
||||
public class DynamicDataSource extends AbstractRoutingDataSource {
|
||||
|
||||
/**
|
||||
* 描述 : 目标数据库
|
||||
*/
|
||||
private static Map<Object, Object> dyanmictargetDataSources;
|
||||
|
||||
/**
|
||||
* 描述 : 当前所使用的数据源
|
||||
*/
|
||||
private static final ThreadLocal<DataSource> CURRENTDATASOURCE = new ThreadLocal<>();
|
||||
|
||||
static {
|
||||
if (null == DynamicDataSource.dyanmictargetDataSources) {
|
||||
DynamicDataSource.dyanmictargetDataSources = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dynamicDataSourceConfig
|
||||
*/
|
||||
@Autowired
|
||||
private DynamicDataSourceConfig dynamicDataSourceConfig;
|
||||
|
||||
/**
|
||||
* 描述 : 数据源构建
|
||||
*/
|
||||
@Autowired
|
||||
private IBuildDataSource buildDataSource;
|
||||
|
||||
/**
|
||||
* 当前所使用的数据源
|
||||
*
|
||||
* @return 数据源
|
||||
*/
|
||||
public static DataSource getCurrentDataSource() {
|
||||
return CURRENTDATASOURCE.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object determineCurrentLookupKey() { //NOSONAR
|
||||
//拿到code
|
||||
String dataSourceCode = DbContextHolder.getDataSourceCode();
|
||||
//判断code是否为空,如果为空,则设置为默认的数据源代码
|
||||
if (StringUtils.isBlank(dataSourceCode)) {
|
||||
dataSourceCode = dynamicDataSourceConfig.getDefaultCode();
|
||||
if (StringUtils.isBlank(dataSourceCode)) {
|
||||
throw new DynamicDataSourceException("you do not specify a data source , current dataSourceCode is null");
|
||||
}
|
||||
log.warn("you do not specify a data source , current dataSourceCode is null , now use defaultCode :" + dataSourceCode);
|
||||
}
|
||||
//拿到数据源属性,并且判断数据源属性是否存在,以及是否可用
|
||||
DataSourceMeta dataSourceProperties = dynamicDataSourceConfig.getMap().get(dataSourceCode);
|
||||
if (dataSourceProperties != null && dataSourceProperties.getEnable()) {
|
||||
Object obj = DynamicDataSource.dyanmictargetDataSources.get(dataSourceCode);
|
||||
if (obj == null) {
|
||||
log.debug(dataSourceCode + " not in the cache, ready to create a data source object");
|
||||
DataSource dataSource = buildDataSource.build(dataSourceProperties);
|
||||
if (dataSource != null) {
|
||||
DynamicDataSource.dyanmictargetDataSources.put(dataSourceCode, dataSource);
|
||||
super.setTargetDataSources(DynamicDataSource.dyanmictargetDataSources);
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
log.debug(dataSourceCode + " data Source has been created and the cache");
|
||||
} else {
|
||||
log.debug(dataSourceCode + " already in the cache can be used directly");
|
||||
}
|
||||
} else {
|
||||
//如果在配置文件中,选择的数据源不存在,则也清理掉数据源缓存(可能是动态删除)
|
||||
if (DynamicDataSource.dyanmictargetDataSources.containsKey(dataSourceCode)) {
|
||||
DynamicDataSource.dyanmictargetDataSources.remove(dataSourceCode);
|
||||
super.setTargetDataSources(DynamicDataSource.dyanmictargetDataSources);
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
throw new DynamicDataSourceException("dataSourceCode : " + dataSourceCode + " not exist or not enable");
|
||||
}
|
||||
log.debug("switch to the Data Source : " + dataSourceCode);
|
||||
Object dataSource = dyanmictargetDataSources.get(dataSourceCode);
|
||||
if (dataSource != null) {
|
||||
CURRENTDATASOURCE.set((DataSource) dataSource);
|
||||
} else {
|
||||
CURRENTDATASOURCE.set(null);
|
||||
}
|
||||
log.debug("Sets the current data source : " + dataSourceCode);
|
||||
return dataSourceCode;
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* DruidDataSourceConfig.java
|
||||
* Created at 2016-11-02
|
||||
* Created by wangkang
|
||||
* Copyright (C) 2016 egridcloud.com, All rights reserved.
|
||||
*/
|
||||
package org.itkk.udf.datasource.dynamic;
|
||||
|
||||
import lombok.Data;
|
||||
import org.itkk.udf.core.domain.datasource.DataSourceMeta;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 描述 : DynamicDataSourceConfig
|
||||
*
|
||||
* @author wangkang
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "org.itkk.datasource.dynamic")
|
||||
@Data
|
||||
public class DynamicDataSourceConfig {
|
||||
|
||||
/**
|
||||
* 描述 : 默认数据代码
|
||||
*/
|
||||
private String defaultCode;
|
||||
|
||||
/**
|
||||
* 描述 : map
|
||||
*/
|
||||
private Map<String, DataSourceMeta> map;
|
||||
|
||||
/**
|
||||
* 描述 : 创建数据源
|
||||
*
|
||||
* @return 数据源
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource dataSource() {
|
||||
DynamicDataSource dynamicDataSource = new DynamicDataSource();
|
||||
dynamicDataSource.setTargetDataSources(new HashMap<>());
|
||||
return dynamicDataSource;
|
||||
}
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package org.itkk.udf.datasource.dynamic;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ClassName: DynamicDataSourceException
|
||||
* </p>
|
||||
* <p>
|
||||
* Description: 动态数据源异常
|
||||
* </p>
|
||||
* <p>
|
||||
* Author: wangkang
|
||||
* </p>
|
||||
* <p>
|
||||
* Date: 2016年3月23日
|
||||
* </p>
|
||||
*/
|
||||
public class DynamicDataSourceException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Field serialVersionUID: 序列号
|
||||
* </p>
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Description: 构造函数
|
||||
* </p>
|
||||
*
|
||||
* @param message 异常信息
|
||||
*/
|
||||
public DynamicDataSourceException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Description: 构造函数
|
||||
* </p>
|
||||
*
|
||||
* @param cause 堆栈
|
||||
*/
|
||||
public DynamicDataSourceException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Description: 构造函数
|
||||
* </p>
|
||||
*
|
||||
* @param message 异常信息
|
||||
* @param cause 堆栈
|
||||
*/
|
||||
public DynamicDataSourceException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.itkk.udf.datasource;
|
||||
package org.itkk.udf.datasource.dynamic;
|
||||
|
||||
import lombok.Data;
|
||||
import org.itkk.udf.core.domain.datasource.DataSourceMeta;
|
||||
Reference in New Issue
Block a user