From 0606363e982c10938bbc38bfc840a9158702d66b Mon Sep 17 00:00:00 2001 From: wangkang Date: Tue, 22 Aug 2017 11:45:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=A8=E6=80=81=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 ++ udf-starter-datasource-dynamic/.checkstyle | 7 ++ udf-starter-datasource-dynamic/.gitignore | 4 + udf-starter-datasource-dynamic/pom.xml | 28 +++++ .../dynamic/DataSourceThreadLocal.java | 18 +++ .../datasource/dynamic/DbContextHolder.java | 51 +++++++++ .../datasource/dynamic/DynamicDataSource.java | 107 ++++++++++++++++++ .../dynamic/DynamicDataSourceConfig.java | 53 +++++++++ .../dynamic/DynamicDataSourceException.java | 60 ++++++++++ .../{ => dynamic}/DataSourceConfig.java | 2 +- 10 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 udf-starter-datasource-dynamic/.checkstyle create mode 100644 udf-starter-datasource-dynamic/.gitignore create mode 100644 udf-starter-datasource-dynamic/pom.xml create mode 100644 udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DataSourceThreadLocal.java create mode 100644 udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DbContextHolder.java create mode 100644 udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSource.java create mode 100644 udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSourceConfig.java create mode 100644 udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSourceException.java rename udf-starter-datasource/src/main/java/org/itkk/udf/datasource/{ => dynamic}/DataSourceConfig.java (95%) diff --git a/pom.xml b/pom.xml index 64ffffc..1ff4018 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ udf-starter-connection-pool-druid udf-starter-qrcode udf-starter-auth + udf-starter-datasource-dynamic @@ -121,6 +122,12 @@ udf-starter-datasource ${udf-starter.version} + + + org.itkk.udf + udf-starter-datasource-dynamic + ${udf-starter.version} + org.itkk.udf diff --git a/udf-starter-datasource-dynamic/.checkstyle b/udf-starter-datasource-dynamic/.checkstyle new file mode 100644 index 0000000..7589bde --- /dev/null +++ b/udf-starter-datasource-dynamic/.checkstyle @@ -0,0 +1,7 @@ + + + + + + + diff --git a/udf-starter-datasource-dynamic/.gitignore b/udf-starter-datasource-dynamic/.gitignore new file mode 100644 index 0000000..c541155 --- /dev/null +++ b/udf-starter-datasource-dynamic/.gitignore @@ -0,0 +1,4 @@ +/target/ +/bin/ +/.classpath +/.project diff --git a/udf-starter-datasource-dynamic/pom.xml b/udf-starter-datasource-dynamic/pom.xml new file mode 100644 index 0000000..925279a --- /dev/null +++ b/udf-starter-datasource-dynamic/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + udf-starter-datasource-dynamic + udf-starter-datasource-dynamic + jar + http://itkk.org:81 + + + org.itkk.udf + udf-starter + 1.0 + + + + + org.itkk.udf + udf-starter-core + + + + org.springframework.boot + spring-boot-starter-jdbc + + + diff --git a/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DataSourceThreadLocal.java b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DataSourceThreadLocal.java new file mode 100644 index 0000000..6aa8fe4 --- /dev/null +++ b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DataSourceThreadLocal.java @@ -0,0 +1,18 @@ +package org.itkk.udf.datasource.dynamic; + +/** + * 描述 : 数据源本地线程 + * + * @author wangkang + */ +public class DataSourceThreadLocal extends ThreadLocal { + /* + * 修改点参考:http://blog.csdn.net/cxh5060/article/details/49275633 + * @see java.lang.ThreadLocal#remove() + */ + @Override + public void remove() { + super.remove(); + this.initialValue(); + } +} diff --git a/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DbContextHolder.java b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DbContextHolder.java new file mode 100644 index 0000000..19343a7 --- /dev/null +++ b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DbContextHolder.java @@ -0,0 +1,51 @@ +package org.itkk.udf.datasource.dynamic; + +/** + * 描述 : DbContextHolder + *

+ * 多个登入用户可能需要同时切换数据源,所以这里需要写一个线程安全的ThreadLocal 用户切换数据源只要在线程中使用 + * + * @author wangkang + */ +public class DbContextHolder { + + /** + * 描述 : 本地线程 + */ + private static final ThreadLocal CONTEXTHOLDER = new DataSourceThreadLocal(); + + /** + * 描述 : 私有构造函数 + */ + private DbContextHolder() { + + } + + /** + * 描述 : 设置数据源代码 + * + * @param code 数据源代码 + */ + public static void setDataSourceCode(String code) { + CONTEXTHOLDER.set(code); + } + + /** + * 描述 : 获取数据源代码 + * + * @return 数据源代码 + */ + public static String getDataSourceCode() { + return CONTEXTHOLDER.get(); + } + + /** + *

+ * Description: 清理数据源代码 + *

+ */ + public static void clearDataSourceCode() { + CONTEXTHOLDER.remove(); + } + +} diff --git a/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSource.java b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSource.java new file mode 100644 index 0000000..6154ddc --- /dev/null +++ b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSource.java @@ -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 dyanmictargetDataSources; + + /** + * 描述 : 当前所使用的数据源 + */ + private static final ThreadLocal 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; + } + +} diff --git a/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSourceConfig.java b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSourceConfig.java new file mode 100644 index 0000000..05f5df0 --- /dev/null +++ b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSourceConfig.java @@ -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 map; + + /** + * 描述 : 创建数据源 + * + * @return 数据源 + */ + @Bean + @Primary + public DataSource dataSource() { + DynamicDataSource dynamicDataSource = new DynamicDataSource(); + dynamicDataSource.setTargetDataSources(new HashMap<>()); + return dynamicDataSource; + } + +} diff --git a/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSourceException.java b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSourceException.java new file mode 100644 index 0000000..85da980 --- /dev/null +++ b/udf-starter-datasource-dynamic/src/main/java/org/itkk/udf/datasource/dynamic/DynamicDataSourceException.java @@ -0,0 +1,60 @@ +package org.itkk.udf.datasource.dynamic; + +/** + *

+ * ClassName: DynamicDataSourceException + *

+ *

+ * Description: 动态数据源异常 + *

+ *

+ * Author: wangkang + *

+ *

+ * Date: 2016年3月23日 + *

+ */ +public class DynamicDataSourceException extends RuntimeException { + + /** + *

+ * Field serialVersionUID: 序列号 + *

+ */ + private static final long serialVersionUID = 1L; + + /** + *

+ * Description: 构造函数 + *

+ * + * @param message 异常信息 + */ + public DynamicDataSourceException(String message) { + super(message); + } + + /** + *

+ * Description: 构造函数 + *

+ * + * @param cause 堆栈 + */ + public DynamicDataSourceException(Throwable cause) { + super(cause); + } + + /** + *

+ * Description: 构造函数 + *

+ * + * @param message 异常信息 + * @param cause 堆栈 + */ + public DynamicDataSourceException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/udf-starter-datasource/src/main/java/org/itkk/udf/datasource/DataSourceConfig.java b/udf-starter-datasource/src/main/java/org/itkk/udf/datasource/dynamic/DataSourceConfig.java similarity index 95% rename from udf-starter-datasource/src/main/java/org/itkk/udf/datasource/DataSourceConfig.java rename to udf-starter-datasource/src/main/java/org/itkk/udf/datasource/dynamic/DataSourceConfig.java index 1a33eff..ba98ca3 100644 --- a/udf-starter-datasource/src/main/java/org/itkk/udf/datasource/DataSourceConfig.java +++ b/udf-starter-datasource/src/main/java/org/itkk/udf/datasource/dynamic/DataSourceConfig.java @@ -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;