Skip to content

Commit

Permalink
✨ 动态添加数据源,动态切换数据源
Browse files Browse the repository at this point in the history
  • Loading branch information
xkcoding committed Sep 4, 2019
1 parent 912bca8 commit ce4fb28
Show file tree
Hide file tree
Showing 26 changed files with 1,029 additions and 0 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<module>spring-boot-demo-codegen</module>
<module>spring-boot-demo-graylog</module>
<module>spring-boot-demo-ldap</module>
<module>spring-boot-demo-dynamic-datasource</module>
</modules>
<packaging>pom</packaging>

Expand Down
31 changes: 31 additions & 0 deletions spring-boot-demo-dynamic-datasource/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/

### VS Code ###
.vscode/
16 changes: 16 additions & 0 deletions spring-boot-demo-dynamic-datasource/db/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CREATE TABLE IF NOT EXISTS `datasource_config`
(
`id` bigint(13) NOT NULL AUTO_INCREMENT COMMENT '主键',
`host` varchar(255) NOT NULL COMMENT '数据库地址',
`port` int(6) NOT NULL COMMENT '数据库端口',
`username` varchar(100) NOT NULL COMMENT '数据库用户名',
`password` varchar(100) NOT NULL COMMENT '数据库密码',
`database` varchar(100) DEFAULT 0 COMMENT '数据库名称',
PRIMARY KEY (`id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8 COMMENT ='数据源配置表';

INSERT INTO `datasource_config`(`id`, `host`, `port`, `username`, `password`, `database`)
VALUES (1, '127.0.01', 3306, 'root', 'root', 'test');
INSERT INTO `datasource_config`(`id`, `host`, `port`, `username`, `password`, `database`)
VALUES (2, '192.168.239.4', 3306, 'dmcp', 'Dmcp321!', 'test');
25 changes: 25 additions & 0 deletions spring-boot-demo-dynamic-datasource/db/user.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
CREATE TABLE IF NOT EXISTS `test_user`
(
`id` bigint(13) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(255) NOT NULL COMMENT '姓名',
PRIMARY KEY (`id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8 COMMENT ='用户表';

-- 默认数据库插入如下 SQL
INSERT INTO `test_user`(`id`, `name`)
values (1, '默认数据库用户1');
INSERT INTO `test_user`(`id`, `name`)
values (2, '默认数据库用户2');

-- 测试库1插入如下SQL
INSERT INTO `test_user`(`id`, `name`)
values (1, '测试库1用户1');
INSERT INTO `test_user`(`id`, `name`)
values (2, '测试库1用户2');

-- 测试库2插入如下SQL
INSERT INTO `test_user`(`id`, `name`)
values (1, '测试库2用户1');
INSERT INTO `test_user`(`id`, `name`)
values (2, '测试库2用户2');
71 changes: 71 additions & 0 deletions spring-boot-demo-dynamic-datasource/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-boot-demo-dynamic-datasource</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-boot-demo-dynamic-datasource</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>com.xkcoding</groupId>
<artifactId>spring-boot-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>spring-boot-demo-dynamic-datasource</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.xkcoding.dynamic.datasource;

import com.xkcoding.dynamic.datasource.datasource.DatasourceConfigCache;
import com.xkcoding.dynamic.datasource.datasource.DatasourceConfigContextHolder;
import com.xkcoding.dynamic.datasource.mapper.DatasourceConfigMapper;
import com.xkcoding.dynamic.datasource.model.DatasourceConfig;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.List;

/**
* <p>
* 启动器
* </p>
*
* @author yangkai.shen
* @date Created in 2019/9/4 17:57
*/
@SpringBootApplication
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SpringBootDemoDynamicDatasourceApplication implements CommandLineRunner {
private final DatasourceConfigMapper configMapper;

public static void main(String[] args) {
SpringApplication.run(SpringBootDemoDynamicDatasourceApplication.class, args);
}

@Override
public void run(String... args) {
DatasourceConfigContextHolder.setDefaultDatasource();
List<DatasourceConfig> datasourceConfigs = configMapper.selectAll();
System.out.println("加载其余数据源配置列表: " + datasourceConfigs);
datasourceConfigs.forEach(config -> DatasourceConfigCache.INSTANCE.addConfig(config.getId(), config));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.xkcoding.dynamic.datasource.annotation;

import java.lang.annotation.*;

/**
* <p>
* 默认数据源
* </p>
*
* @author yangkai.shen
* @date Created in 2019/9/4 17:37
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DefaultDatasource {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.xkcoding.dynamic.datasource.aspect;

import com.xkcoding.dynamic.datasource.annotation.DefaultDatasource;
import com.xkcoding.dynamic.datasource.datasource.DatasourceConfigContextHolder;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
* <p>
* 数据源选择器切面
* </p>
*
* @author yangkai.shen
* @date Created in 2019/9/4 16:52
*/
@Aspect
@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class DatasourceSelectorAspect {
@Pointcut("execution(public * com.xkcoding.dynamic.datasource.controller.*.*(..))")
public void datasourcePointcut() {
}

/**
* 前置通知 用于拦截操作
*/
@Before("datasourcePointcut()")
public void doBefore(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();

DefaultDatasource annotation = method.getAnnotation(DefaultDatasource.class);
if (null != annotation) {
DatasourceConfigContextHolder.setDefaultDatasource();
} else {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = attributes.getRequest();
String configIdInHeader = request.getHeader("Datasource-Config-Id");
if (StringUtils.hasText(configIdInHeader)) {
long configId = Long.parseLong(configIdInHeader);
DatasourceConfigContextHolder.setCurrentDatasourceConfig(configId);
} else {
DatasourceConfigContextHolder.setDefaultDatasource();
}
}
}

@AfterReturning("datasourcePointcut()")
public void doAfter() {
DatasourceConfigContextHolder.setDefaultDatasource();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.xkcoding.dynamic.datasource.config;

import com.xkcoding.dynamic.datasource.datasource.DynamicDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
* <p>
* 数据源配置
* </p>
*
* @author yangkai.shen
* @date Created in 2019/9/4 10:27
*/
@Configuration
public class DatasourceConfiguration {

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.type(DynamicDataSource.class);
return dataSourceBuilder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.xkcoding.dynamic.datasource.config;

import tk.mybatis.mapper.annotation.RegisterMapper;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

/**
* <p>
* 通用 mapper 自定义 mapper 文件
* </p>
*
* @author yangkai.shen
* @date Created in 2019/9/4 16:23
*/
@RegisterMapper
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.xkcoding.dynamic.datasource.config;

import lombok.SneakyThrows;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.annotation.MapperScan;

import javax.sql.DataSource;

/**
* <p>
* mybatis配置
* </p>
*
* @author yangkai.shen
* @date Created in 2019/9/4 16:20
*/
@Configuration
@MapperScan(basePackages = "com.xkcoding.dynamicdatasource.mapper", sqlSessionFactoryRef = "sqlSessionFactory")
public class MybatisConfiguration {
/**
* 创建会话工厂。
*
* @param dataSource 数据源
* @return 会话工厂
*/
@Bean(name = "sqlSessionFactory")
@SneakyThrows
public SqlSessionFactory getSqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
}
Loading

0 comments on commit ce4fb28

Please sign in to comment.