初始化提交
This commit is contained in:
@ -0,0 +1,18 @@
|
||||
package business.cooperop.base.datasource.mysql.common;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2020/7/24 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface MultiDataSource {
|
||||
String name() default "main";
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
package business.cooperop.base.datasource.mysql.config;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2020/7/24 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.util.JdbcConstants;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "spring.datasource")
|
||||
@Setter
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class DruidProperties {
|
||||
public DruidProperties() {
|
||||
log.info("default 数据源加载");
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源名称
|
||||
*/
|
||||
private String datasourceName = "main";
|
||||
|
||||
private String url;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
/**
|
||||
* 默认为 MYSQL 8.x 配置
|
||||
*/
|
||||
private String driverClassName;
|
||||
|
||||
private Integer initialSize = 10;
|
||||
|
||||
private Integer minIdle = 3;
|
||||
|
||||
private Integer maxActive = 60;
|
||||
|
||||
private Integer maxWait = 60000;
|
||||
|
||||
private Boolean removeAbandoned = true;
|
||||
|
||||
private Integer removeAbandonedTimeout = 180;
|
||||
|
||||
private Integer timeBetweenEvictionRunsMillis = 60000;
|
||||
|
||||
private Integer minEvictableIdleTimeMillis = 300000;
|
||||
|
||||
private String validationQuery = "SELECT 'x'";
|
||||
|
||||
private Boolean testWhileIdle = true;
|
||||
|
||||
private Boolean testOnBorrow = false;
|
||||
|
||||
private Boolean testOnReturn = false;
|
||||
|
||||
private Boolean poolPreparedStatements = true;
|
||||
|
||||
private Integer maxPoolPreparedStatementPerConnectionSize = 50;
|
||||
|
||||
private String filters = "stat";
|
||||
|
||||
public DruidDataSource config() {
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
return config(dataSource);
|
||||
}
|
||||
|
||||
public DruidDataSource config(DruidDataSource dataSource) {
|
||||
dataSource.setDbType(JdbcConstants.SQL_SERVER);
|
||||
dataSource.setUrl(url);
|
||||
dataSource.setUsername(username);
|
||||
dataSource.setPassword(password);
|
||||
dataSource.setDriverClassName(driverClassName);
|
||||
dataSource.setInitialSize(initialSize); // 定义初始连接数
|
||||
dataSource.setMinIdle(minIdle); // 最小空闲
|
||||
dataSource.setMaxActive(maxActive); // 定义最大连接数
|
||||
dataSource.setMaxWait(maxWait); // 获取连接等待超时的时间
|
||||
dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收
|
||||
dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长
|
||||
|
||||
// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
|
||||
// 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
|
||||
// 用来检测连接是否有效的sql,要求是一个查询语句
|
||||
dataSource.setValidationQuery(validationQuery);
|
||||
// 申请连接的时候检测
|
||||
dataSource.setTestWhileIdle(testWhileIdle);
|
||||
// 申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能
|
||||
dataSource.setTestOnBorrow(testOnBorrow);
|
||||
// 归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能
|
||||
dataSource.setTestOnReturn(testOnReturn);
|
||||
// 打开PSCache,并且指定每个连接上PSCache的大小
|
||||
dataSource.setPoolPreparedStatements(poolPreparedStatements);
|
||||
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
|
||||
// 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
|
||||
// 监控统计用的filter:stat
|
||||
// 日志用的filter:log4j
|
||||
// 防御SQL注入的filter:wall
|
||||
try {
|
||||
dataSource.setFilters(filters);
|
||||
} catch (SQLException e) {
|
||||
log.error("扩展插件失败.{}", e.getMessage());
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package business.cooperop.base.datasource.mysql.config;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2020/7/24 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
public class DynamicDataSource extends AbstractRoutingDataSource {
|
||||
/**
|
||||
* <p>多 datasource 的上下文</p>
|
||||
* <p>每个线程独立的数据库连接名称</p>
|
||||
*/
|
||||
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
|
||||
|
||||
/**
|
||||
* @param dataSourceDbName 数据库别名
|
||||
* @Description: 设置数据源别名
|
||||
*/
|
||||
public static void setDataSourceDbName(String dataSourceDbName) {
|
||||
contextHolder.set(dataSourceDbName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 获取数据源别名
|
||||
*/
|
||||
public static String getDataSourceDbName() {
|
||||
return contextHolder.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 清除数据源别名
|
||||
*/
|
||||
public static void clearDataSourceDbName() {
|
||||
contextHolder.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写获取连接名称的方法
|
||||
*
|
||||
* @return 连接名称
|
||||
*/
|
||||
@Override
|
||||
protected Object determineCurrentLookupKey() {
|
||||
return getDataSourceDbName();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package business.cooperop.base.datasource.mysql.config;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2020/7/24 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
|
||||
import business.cooperop.base.datasource.mysql.common.MultiDataSource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "business.cooperop.base", name = "multiDatasourceOpen", havingValue = "true")
|
||||
@Slf4j
|
||||
public class MultiDataSourceAop implements Ordered {
|
||||
|
||||
|
||||
public MultiDataSourceAop() {
|
||||
log.info("多数据源初始化 AOP ");
|
||||
}
|
||||
|
||||
@Pointcut(value = "@annotation(business.cooperop.base.datasource.mysql.common.MultiDataSource)")
|
||||
private void cut() {
|
||||
}
|
||||
|
||||
@Around("cut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
|
||||
Signature signature = point.getSignature();
|
||||
MethodSignature methodSignature;
|
||||
if (!(signature instanceof MethodSignature)) {
|
||||
throw new IllegalArgumentException("该注解只能用于方法");
|
||||
}
|
||||
methodSignature = (MethodSignature) signature;
|
||||
//获取当前方法的注解
|
||||
Object target = point.getTarget();
|
||||
Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
|
||||
MultiDataSource datasource = currentMethod.getAnnotation(MultiDataSource.class);
|
||||
if (datasource != null) {
|
||||
DynamicDataSource.setDataSourceDbName(datasource.name());
|
||||
log.info("设置数据源为:" + datasource.name());
|
||||
} else {
|
||||
DynamicDataSource.setDataSourceDbName("main");
|
||||
log.info("设置数据源为:默认 --> main");
|
||||
}
|
||||
try {
|
||||
return point.proceed();
|
||||
} finally {
|
||||
log.info("清空数据源信息!");
|
||||
DynamicDataSource.clearDataSourceDbName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* aop的顺序要早于spring的事务
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package business.cooperop.base.datasource.mysql.config;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2020/7/24 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "business.cooperop.base")
|
||||
@Getter
|
||||
@Setter
|
||||
@Slf4j
|
||||
public class MultiDataSourceConfig {
|
||||
public MultiDataSourceConfig() {
|
||||
log.info("加载多数据源配置信息 --> {}", "business.cooperop.base");
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个数据源
|
||||
*/
|
||||
private List<DruidProperties> datasource;
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
package business.cooperop.base.datasource.mysql.config;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2020/7/24 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class MultiSourceConfig {
|
||||
|
||||
@Autowired
|
||||
private DruidProperties druidProperties;
|
||||
|
||||
@Autowired
|
||||
private MultiDataSourceConfig multiDataSourceConfig;
|
||||
|
||||
|
||||
/**
|
||||
* 单数据源连接池配置
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "business.cooperop.base.multiDatasourceOpen", havingValue = "false")
|
||||
public DruidDataSource singleDatasource() {
|
||||
log.info("singleDatasource");
|
||||
return druidProperties.config(new DruidDataSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* 多数据源连接池配置
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "business.cooperop.base.multiDatasourceOpen", havingValue = "true")
|
||||
public DynamicDataSource mutiDataSource() {
|
||||
log.info("mutiDataSource");
|
||||
|
||||
//存储数据源别名与数据源的映射
|
||||
HashMap<Object, Object> dbNameMap = new HashMap();
|
||||
// 核心数据源
|
||||
DruidDataSource mainDataSource = druidProperties.config();
|
||||
// 这里添加 主要数据库,其它数据库挂了,默认使用主数据库
|
||||
dbNameMap.put("main", mainDataSource);
|
||||
// 其它数据源
|
||||
// 当前多数据源是否存在
|
||||
if (multiDataSourceConfig.getDatasource() != null) {
|
||||
//过滤掉没有添加 datasourceName 的数据源,先加载娟全局配置,再次加载当前配置
|
||||
List<DruidDataSource> multiDataSourceList = multiDataSourceConfig.getDatasource().stream()
|
||||
.filter(dp -> !"".equals(Optional.ofNullable(dp.getDatasourceName()).orElse("")))
|
||||
.map(dp -> {
|
||||
DruidDataSource druidDataSource = dp.config(druidProperties.config());
|
||||
dbNameMap.put(dp.getDatasourceName(), druidDataSource);
|
||||
return druidDataSource;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 测试所有的数据源
|
||||
try {
|
||||
mainDataSource.init();
|
||||
for (DruidDataSource druidDataSource : multiDataSourceList) {
|
||||
druidDataSource.init();
|
||||
}
|
||||
} catch (SQLException sql) {
|
||||
log.error("======================= 多数据源配置错误 ==========================");
|
||||
sql.printStackTrace();
|
||||
}
|
||||
}
|
||||
DynamicDataSource dynamicDataSource = new DynamicDataSource();
|
||||
dynamicDataSource.setTargetDataSources(dbNameMap);
|
||||
dynamicDataSource.setDefaultTargetDataSource(mainDataSource);
|
||||
return dynamicDataSource;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user