添加动态数据源

This commit is contained in:
wangkang
2017-08-22 11:45:37 +08:00
parent cb11f6eba8
commit 0606363e98
10 changed files with 336 additions and 1 deletions
+7
View File
@@ -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
+28
View File
@@ -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>
@@ -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();
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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,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;