Browse Source

feat: 🆕 新增多数据源功能

dynamicDs
施海荣 1 year ago
parent
commit
971b91329f
11 changed files with 455 additions and 1 deletions
  1. +2
    -1
      pom.xml
  2. +26
    -0
      ym-dynamic-datasource/pom.xml
  3. +11
    -0
      ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/annotation/DataSource.java
  4. +57
    -0
      ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/aspect/DataSourceAspect.java
  5. +44
    -0
      ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/config/DynamicContextHolder.java
  6. +12
    -0
      ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/config/DynamicDataSource.java
  7. +50
    -0
      ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/config/DynamicDataSourceConfig.java
  8. +40
    -0
      ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/config/DynamicDataSourceFactory.java
  9. +188
    -0
      ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/properties/DataSourceProperties.java
  10. +20
    -0
      ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/properties/DynamicDataSourceProperties.java
  11. +5
    -0
      ym-gateway/pom.xml

+ 2
- 1
pom.xml View File

@@ -18,6 +18,7 @@
<module>ym-websocket</module>
<module>ym-packing</module>
<module>ym-s7</module>
<module>ym-dynamic-datasource</module>
</modules>
<packaging>pom</packaging>

@@ -241,4 +242,4 @@
</pluginRepository>
</pluginRepositories>

</project>
</project>

+ 26
- 0
ym-dynamic-datasource/pom.xml View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ym-pass</artifactId>
<groupId>com.cnbm</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ym-dynamic-datasource</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


<build>
<finalName>${project.artifactId}</finalName>
</build>


</project>

+ 11
- 0
ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/annotation/DataSource.java View File

@@ -0,0 +1,11 @@
package com.cnbm.dynamic.datasource.annotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource {
String value() default "";
}

+ 57
- 0
ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/aspect/DataSourceAspect.java View File

@@ -0,0 +1,57 @@
package com.cnbm.dynamic.datasource.aspect;

import com.cnbm.dynamic.datasource.annotation.DataSource;
import com.cnbm.dynamic.datasource.config.DynamicContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DataSourceAspect {
protected Logger logger = LoggerFactory.getLogger(getClass());

@Pointcut("@annotation(com.cnbm.dynamic.datasource.annotation.DataSource) " +
"|| @within(com.cnbm.dynamic.datasource.annotation.DataSource)")
public void dataSourcePointCut() {

}

@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Class targetClass = point.getTarget().getClass();
Method method = signature.getMethod();

DataSource targetDataSource = (DataSource)targetClass.getAnnotation(DataSource.class);
DataSource methodDataSource = method.getAnnotation(DataSource.class);
if(targetDataSource != null || methodDataSource != null){
String value;
if(methodDataSource != null){
value = methodDataSource.value();
}else {
value = targetDataSource.value();
}

DynamicContextHolder.push(value);
logger.debug("set datasource is {}", value);
}

try {
return point.proceed();
} finally {
DynamicContextHolder.poll();
logger.debug("clean datasource");
}
}
}

+ 44
- 0
ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/config/DynamicContextHolder.java View File

@@ -0,0 +1,44 @@
package com.cnbm.dynamic.datasource.config;

import java.util.ArrayDeque;
import java.util.Deque;

public class DynamicContextHolder {
@SuppressWarnings("unchecked")
private static final ThreadLocal<Deque<String>> CONTEXT_HOLDER = new ThreadLocal() {
@Override
protected Object initialValue() {
return new ArrayDeque();
}
};

/**
* 获得当前线程数据源
*
* @return 数据源名称
*/
public static String peek() {
return CONTEXT_HOLDER.get().peek();
}

/**
* 设置当前线程数据源
*
* @param dataSource 数据源名称
*/
public static void push(String dataSource) {
CONTEXT_HOLDER.get().push(dataSource);
}

/**
* 清空当前线程数据源
*/
public static void poll() {
Deque<String> deque = CONTEXT_HOLDER.get();
deque.poll();
if (deque.isEmpty()) {
CONTEXT_HOLDER.remove();
}
}

}

+ 12
- 0
ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/config/DynamicDataSource.java View File

@@ -0,0 +1,12 @@
package com.cnbm.dynamic.datasource.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

@Override
protected Object determineCurrentLookupKey() {
return DynamicContextHolder.peek();
}

}

+ 50
- 0
ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/config/DynamicDataSourceConfig.java View File

@@ -0,0 +1,50 @@
package com.cnbm.dynamic.datasource.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.cnbm.dynamic.datasource.properties.DataSourceProperties;
import com.cnbm.dynamic.datasource.properties.DynamicDataSourceProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
public class DynamicDataSourceConfig {
@Autowired
private DynamicDataSourceProperties properties;

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}

@Bean
public DynamicDataSource dynamicDataSource(DataSourceProperties dataSourceProperties) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(getDynamicDataSource());

//默认数据源
DruidDataSource defaultDataSource = DynamicDataSourceFactory.buildDruidDataSource(dataSourceProperties);
dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);

return dynamicDataSource;
}

private Map<Object, Object> getDynamicDataSource(){
Map<String, DataSourceProperties> dataSourcePropertiesMap = properties.getDatasource();
Map<Object, Object> targetDataSources = new HashMap<>(dataSourcePropertiesMap.size());
dataSourcePropertiesMap.forEach((k, v) -> {
DruidDataSource druidDataSource = DynamicDataSourceFactory.buildDruidDataSource(v);
targetDataSources.put(k, druidDataSource);
});

return targetDataSources;
}

}

+ 40
- 0
ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/config/DynamicDataSourceFactory.java View File

@@ -0,0 +1,40 @@
package com.cnbm.dynamic.datasource.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.cnbm.dynamic.datasource.properties.DataSourceProperties;

import java.sql.SQLException;

public class DynamicDataSourceFactory {

public static DruidDataSource buildDruidDataSource(DataSourceProperties properties) {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(properties.getDriverClassName());
druidDataSource.setUrl(properties.getUrl());
druidDataSource.setUsername(properties.getUsername());
druidDataSource.setPassword(properties.getPassword());

druidDataSource.setInitialSize(properties.getInitialSize());
druidDataSource.setMaxActive(properties.getMaxActive());
druidDataSource.setMinIdle(properties.getMinIdle());
druidDataSource.setMaxWait(properties.getMaxWait());
druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis());
druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis());
druidDataSource.setMaxEvictableIdleTimeMillis(properties.getMaxEvictableIdleTimeMillis());
druidDataSource.setValidationQuery(properties.getValidationQuery());
druidDataSource.setValidationQueryTimeout(properties.getValidationQueryTimeout());
druidDataSource.setTestOnBorrow(properties.isTestOnBorrow());
druidDataSource.setTestOnReturn(properties.isTestOnReturn());
druidDataSource.setPoolPreparedStatements(properties.isPoolPreparedStatements());
druidDataSource.setMaxOpenPreparedStatements(properties.getMaxOpenPreparedStatements());
druidDataSource.setSharePreparedStatements(properties.isSharePreparedStatements());

try {
druidDataSource.setFilters(properties.getFilters());
druidDataSource.init();
} catch (SQLException e) {
e.printStackTrace();
}
return druidDataSource;
}
}

+ 188
- 0
ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/properties/DataSourceProperties.java View File

@@ -0,0 +1,188 @@
package com.cnbm.dynamic.datasource.properties;

public class DataSourceProperties {
private String driverClassName;
private String url;
private String username;
private String password;

/**
* Druid默认参数
*/
private int initialSize = 2;
private int maxActive = 10;
private int minIdle = -1;
private long maxWait = 60 * 1000L;
private long timeBetweenEvictionRunsMillis = 60 * 1000L;
private long minEvictableIdleTimeMillis = 1000L * 60L * 30L;
private long maxEvictableIdleTimeMillis = 1000L * 60L * 60L * 7;
private String validationQuery = "select 1";
private int validationQueryTimeout = -1;
private boolean testOnBorrow = false;
private boolean testOnReturn = false;
private boolean testWhileIdle = true;
private boolean poolPreparedStatements = false;
private int maxOpenPreparedStatements = -1;
private boolean sharePreparedStatements = false;
private String filters = "stat,wall";

public String getDriverClassName() {
return driverClassName;
}

public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public int getInitialSize() {
return initialSize;
}

public void setInitialSize(int initialSize) {
this.initialSize = initialSize;
}

public int getMaxActive() {
return maxActive;
}

public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}

public int getMinIdle() {
return minIdle;
}

public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}

public long getMaxWait() {
return maxWait;
}

public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
}

public long getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
}

public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}

public long getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
}

public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}

public long getMaxEvictableIdleTimeMillis() {
return maxEvictableIdleTimeMillis;
}

public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
}

public String getValidationQuery() {
return validationQuery;
}

public void setValidationQuery(String validationQuery) {
this.validationQuery = validationQuery;
}

public int getValidationQueryTimeout() {
return validationQueryTimeout;
}

public void setValidationQueryTimeout(int validationQueryTimeout) {
this.validationQueryTimeout = validationQueryTimeout;
}

public boolean isTestOnBorrow() {
return testOnBorrow;
}

public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}

public boolean isTestOnReturn() {
return testOnReturn;
}

public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}

public boolean isTestWhileIdle() {
return testWhileIdle;
}

public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}

public boolean isPoolPreparedStatements() {
return poolPreparedStatements;
}

public void setPoolPreparedStatements(boolean poolPreparedStatements) {
this.poolPreparedStatements = poolPreparedStatements;
}

public int getMaxOpenPreparedStatements() {
return maxOpenPreparedStatements;
}

public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) {
this.maxOpenPreparedStatements = maxOpenPreparedStatements;
}

public boolean isSharePreparedStatements() {
return sharePreparedStatements;
}

public void setSharePreparedStatements(boolean sharePreparedStatements) {
this.sharePreparedStatements = sharePreparedStatements;
}

public String getFilters() {
return filters;
}

public void setFilters(String filters) {
this.filters = filters;
}
}

+ 20
- 0
ym-dynamic-datasource/src/main/java/com/cnbm/dynamic/datasource/properties/DynamicDataSourceProperties.java View File

@@ -0,0 +1,20 @@
package com.cnbm.dynamic.datasource.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.LinkedHashMap;
import java.util.Map;

@ConfigurationProperties(prefix = "dynamic")
public class DynamicDataSourceProperties {
private Map<String, DataSourceProperties> datasource = new LinkedHashMap<>();

public Map<String, DataSourceProperties> getDatasource() {
return datasource;
}

public void setDatasource(Map<String, DataSourceProperties> datasource) {
this.datasource = datasource;
}
}


+ 5
- 0
ym-gateway/pom.xml View File

@@ -67,6 +67,11 @@
<artifactId>ym-websocket</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.cnbm</groupId>
<artifactId>ym-dynamic-datasource</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>


Loading…
Cancel
Save