Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop yongzhao qcc #237

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions common/dynamic-datasource/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?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>cloud</artifactId>
<groupId>com.springboot.cloud</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>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>

<dependencies>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.4.1</version>
</dependency>

<!-- spring-boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.1.10.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.10.RELEASE</version>
</dependency>

<!-- postgresql驱动 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.5</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
</dependency>

<!-- druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.24</version>
</dependency>

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>4.0</version>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>

<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.springboot.cloud.annotation;

import java.lang.annotation.*;

/**
* 注解 切换
* @author zhaoyong
* @date 2022年6月9日 16点39分
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SwitchDatabase {
String value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.springboot.cloud.aspec;

import com.springboot.cloud.annotation.SwitchDatabase;
import com.springboot.cloud.context.DynamicDataSourceContext;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


/**
* @author zhaoy
*/
@Order(0)
@Aspect
@Component
public class DataSourceAspect {

@Pointcut("@annotation(com.springboot.cloud.annotation.SwitchDatabase)")
public void point() {

}

@Before("point()&&@annotation(source)")
public void before(SwitchDatabase source) {
DynamicDataSourceContext.cut(source.value());
}

@After("point()")
public void after() {
DynamicDataSourceContext.remove();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.springboot.cloud.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.springboot.cloud.context.DynamicDataSourceContext;
import com.springboot.cloud.properties.PropertiesManager;

import javax.sql.DataSource;

;

/**
* 数据源配置类,在tomcat启动时触发,在该类中生成多个数据源实例并将其注入到 ApplicationContext 中
* @author zhaoyong
*/
public class DataSourceConfigurer {

public static DataSource getDataSource(String databaseName){
DruidDataSource dataSource = new DruidDataSource();
try {
String dirverName = PropertiesManager.getString("clean."+databaseName+".driverClassName");
dataSource.setDriverClassName(dirverName);
dataSource.setUrl(PropertiesManager.getString("clean."+databaseName+".url"));
dataSource.setUsername(PropertiesManager.getString("clean."+databaseName+".username"));
dataSource.setPassword(PropertiesManager.getString("clean."+databaseName+".password"));
// 最大连接等待
dataSource.setMaxWait(60000);

// 连接数配置
dataSource.setInitialSize(1);
dataSource.setMinIdle(1);
dataSource.setMaxActive(50);
// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
dataSource.setTimeBetweenEvictionRunsMillis(2000);
// 配置一个连接在池中最小生存的时间,单位是毫秒
dataSource.setMinEvictableIdleTimeMillis(600000);
dataSource.setMaxEvictableIdleTimeMillis(900000);

// 检验连接是否有效的查询语句。
dataSource.setValidationQuery("select 1");
// 指明是否在归还到池中前进行检验
dataSource.setTestOnReturn(false);
dataSource.setTestWhileIdle(true);
// 指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个.
dataSource.setTestOnBorrow(true);
dataSource.setDefaultAutoCommit(true);

// 打开后,增强timeBetweenEvictionRunsMillis的周期性连接检查,minIdle内的空闲连接,每次检查强制验证连接有效性
dataSource.setKeepAlive(true);
// 数据源名称
dataSource.setName(databaseName);
DynamicDataSourceContext.add(databaseName);
return dataSource;
}catch (Exception e){
return null;
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.springboot.cloud.config;

import com.springboot.cloud.context.DynamicDataSource;
import com.springboot.cloud.properties.PropertiesManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
* @author zhaoyong
*/
@Configuration
public class DynamicDatasourceConfig {
public static final String CLEAN_DB_CONNECTIONS = "clean.db.connections";
/**
* spring boot 启动后将自定义创建好的数据源对象放到TargetDataSources中用于后续的切换数据源用
* 同时指定默认数据源连接
* @return 动态数据源对象
*/
@Bean
public DynamicDataSource dynamicDataSource() {
DynamicDataSource sources = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
String cleanDbConnections = PropertiesManager.getString(CLEAN_DB_CONNECTIONS);
List<String> dbList = Arrays.asList(cleanDbConnections.split(",").clone());
dbList.stream().forEach(db->{
DataSource dataSource = DataSourceConfigurer.getDataSource(db);
if(dataSource != null) {
targetDataSources.put(db, dataSource);
}
});
sources.setTargetDataSources(targetDataSources);
sources.afterPropertiesSet();
return sources;
}

/**
* 将动态数据源添加到事务管理器中,并生成新的bean
* @return the platform transaction manager
*/
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.springboot.cloud.context;

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

/**
* @author zhaoy
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContext.current() == null? "db_test" : DynamicDataSourceContext.current();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.springboot.cloud.context;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* @author zhaoyong
*/
public class DynamicDataSourceContext {

private static final ThreadLocal<String> NAMES = new ThreadLocal<>();

private static final List<String> BALANCED = new ArrayList<>();

private static Integer index;

private static Lock lock = new ReentrantLock();

/**
* 获取数据源的名称
*
* @return 当前数据源的名称
*/
public static String current() {
return NAMES.get();
}

/**
* 切换数据源
*
* @param name 数据源的名称
*/
public static void cut(String name) {
NAMES.set(name);
}

/**
* 清除当前数据源
*/
public static void remove() {
NAMES.remove();
}

/**
* 添加数据源到负载均衡列表
*
* @param name 数据源名称
*/
public static void add(String name) {
BALANCED.add(name);
index = 0;
}

/**
* 负载均衡策略:切换到参与负载均衡数据源中的某一个数据源
*/
private static void cut() {
if (null == index) {
throw new NullPointerException("没有设置负载均衡数据源");
}

if (lock.tryLock()) {
try {
index = index == BALANCED.size() ? 0 : index;
NAMES.set(BALANCED.get(index));
index++;
} finally {
lock.unlock();
}
} else {
NAMES.set(BALANCED.get(new Random().nextInt(BALANCED.size())));
}
}
}
Loading