This commit is contained in:
iizmg
2020-04-26 10:01:05 +08:00
parent 586a01951f
commit 00c53734b3
10 changed files with 304 additions and 2 deletions
+2
View File
@@ -4,3 +4,5 @@
/udf-starter/udf-starter.iml
/udf-starter/udf-starter-core/target/
/udf-starter/udf-starter-core/udf-starter-core.iml
/udf-starter/udf-starter-datasource-dynamic/udf-starter-datasource-dynamic.iml
/udf-starter/udf-starter-datasource-dynamic/target/
+2 -2
View File
@@ -11,7 +11,7 @@
<url>https://itkk.org/</url>
<!-- 公共参数 -->
<properties>
<udf-starter.version>1.0.5</udf-starter.version>
<udf-starter.version>1.0.0</udf-starter.version>
<springboot.version>2.2.5.RELEASE</springboot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
@@ -30,7 +30,7 @@
<!--子模块 -->
<modules>
<module>udf-starter-core</module>
<!-- <module>udf-starter-datasource-dynamic</module>-->
<module>udf-starter-datasource-dynamic</module>
<!-- <module>udf-starter-process-activiti</module>-->
<!-- <module>udf-starter-cache-redis</module>-->
<!-- <module>udf-starter-cache-db</module>-->
@@ -0,0 +1,24 @@
<?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>https://www.itkk.org/</url>
<!-- 父依赖 -->
<parent>
<groupId>org.itkk.udf</groupId>
<artifactId>udf-starter</artifactId>
<version>1.0.0</version>
</parent>
<!-- 依赖 -->
<dependencies>
<!-- udf-starter-core -->
<dependency>
<groupId>org.itkk.udf</groupId>
<artifactId>udf-starter-core</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,14 @@
package org.itkk.udf.starter.datasource.dynamic;
/**
* 描述 : 数据源本地线程
*
* @author wangkang
*/
public class DataSourceThreadLocal extends ThreadLocal<String> {
@Override
public void remove() {
super.remove();
this.initialValue();
}
}
@@ -0,0 +1,51 @@
package org.itkk.udf.starter.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,10 @@
package org.itkk.udf.starter.datasource.dynamic;
import java.lang.annotation.*;
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DbSwitch {
String value();
}
@@ -0,0 +1,51 @@
package org.itkk.udf.starter.datasource.dynamic;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
@Slf4j
public class DbSwitchAspect {
/**
* 描述 : dbSwitchAspect
*/
@Pointcut("@annotation(org.itkk.udf.starter.datasource.dynamic.DbSwitch)")
public void pointCut() {
}
/**
* 环绕通知
* @param pjd pjd
* @return Object
* @throws Throwable Throwable
*/
@Around("pointCut()")
public Object around(ProceedingJoinPoint pjd) throws Throwable {
try {
Signature signature = pjd.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method.isAnnotationPresent(DbSwitch.class)) {
DbSwitch dbSwitch = method.getAnnotation(DbSwitch.class);
String code = dbSwitch.value();
if (StringUtils.isNotBlank(code)) {
DbContextHolder.setDataSourceCode(code);
}
}
return pjd.proceed();
} finally {
DbContextHolder.clearDataSourceCode();
}
}
}
@@ -0,0 +1,77 @@
package org.itkk.udf.starter.datasource.dynamic;
import org.itkk.udf.starter.core.CoreUtil;
import org.itkk.udf.starter.core.datasource.DataSourceMeta;
import org.itkk.udf.starter.core.datasource.IBuildDataSource;
import org.itkk.udf.starter.core.exception.SystemRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 动态数据源
*/
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* 描述 : 目标数据库
*/
private static Map<Object, Object> dyanmictargetDataSources = new ConcurrentHashMap<>();
/**
* 描述 : 动态数据源参数
*/
@Autowired
private DynamicDataSourceProperties dynamicDataSourceProperties;
/**
* 描述 : 数据源构建
*/
@Autowired
private IBuildDataSource buildDataSource;
@Override
protected Object determineCurrentLookupKey() {
//拿到code
String dataSourceCode = DbContextHolder.getDataSourceCode();
//判断code是否为空,如果为空,则设置为默认的数据源代码
if (StringUtils.isBlank(dataSourceCode)) {
dataSourceCode = dynamicDataSourceProperties.getDefaultCode();
if (StringUtils.isBlank(dataSourceCode)) {
throw new SystemRuntimeException("you do not specify a data source , current dataSourceCode is null");
}
}
//拿到数据源属性,并且判断数据源属性是否存在,以及是否可用
DataSourceMeta dataSourceProperties = dynamicDataSourceProperties.getMap().get(dataSourceCode);
if (dataSourceProperties != null && dataSourceProperties.getEnable()) {
Object obj = DynamicDataSource.dyanmictargetDataSources.get(dataSourceCode);
if (obj == null) {
DataSource dataSource = buildDataSource.build(dataSourceProperties);
if (dataSource != null) {
DynamicDataSource.dyanmictargetDataSources.put(dataSourceCode, dataSource);
super.setTargetDataSources(DynamicDataSource.dyanmictargetDataSources);
super.afterPropertiesSet();
}
}
} else {
//如果在配置文件中,选择的数据源不存在,则也清理掉数据源缓存(可能是动态删除)
if (DynamicDataSource.dyanmictargetDataSources.containsKey(dataSourceCode)) {
DynamicDataSource.dyanmictargetDataSources.remove(dataSourceCode);
super.setTargetDataSources(DynamicDataSource.dyanmictargetDataSources);
super.afterPropertiesSet();
}
throw new SystemRuntimeException("dataSourceCode : " + dataSourceCode + " not exist or not enable");
}
if(log.isDebugEnabled()) {
log.debug("{} switch to the Data Source : {}", CoreUtil.getTraceId(), dataSourceCode);
}
return dataSourceCode;
}
}
@@ -0,0 +1,37 @@
/**
* DruidDataSourceConfig.java
* Created at 2016-11-02
* Created by wangkang
* Copyright (C) 2016 egridcloud.com, All rights reserved.
*/
package org.itkk.udf.starter.datasource.dynamic;
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;
/**
* 描述 : DynamicDataSourceConfig
*
* @author wangkang
*/
@Configuration
public class DynamicDataSourceConfiguration {
/**
* 构造数据源
*
* @return DataSource
*/
@Bean
@Primary
public DataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(new HashMap<>());
return dynamicDataSource;
}
}
@@ -0,0 +1,36 @@
package org.itkk.udf.starter.datasource.dynamic;
import org.itkk.udf.starter.core.datasource.DataSourceMeta;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Map;
@Component
@ConfigurationProperties(prefix = DynamicDataSourceProperties.DYNAMIC_DATASOURCE_PROPERTIES_PRE_FIX)
@Validated
@Data
public class DynamicDataSourceProperties {
/**
* 配置文件前缀
*/
protected static final String DYNAMIC_DATASOURCE_PROPERTIES_PRE_FIX = "org.itkk.udf.starter.datasource.dynamic.properties";
/**
* 默认数据代码
*/
@NotBlank(message = DYNAMIC_DATASOURCE_PROPERTIES_PRE_FIX + ".defaultCode不能为空")
private String defaultCode;
/**
* 数据源配置
*/
@NotNull(message = DYNAMIC_DATASOURCE_PROPERTIES_PRE_FIX + ".map不能为空")
private Map<String, DataSourceMeta> map;
}