在实际的项目开发过程中可能会用到多个数据源,下面所描述的是使用AOP和自定义注解来实现数据源的动态切换。
demo的目录结构如下:
1.自定义数据源注解以及数据源枚举类:
package cn.huangyk.datasourceswitch.config;
import java.lang.annotation.*;
/**
* 自定义数据源类型注解
* @author huangyk
* @version 1.0
* @since 2019/7/20
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
public @interface DBType {
DBTypeEnum type();
}
package cn.huangyk.datasourceswitch.config;
/**
* 自定义数据源类型枚举类
* @author huangyk
* @version 1.0
* @since 2019/7/20
*/
public enum DBTypeEnum {
MYSQL,MYCAT;
}
数据源类型可根据实际需要添加修改。
2.动态路由实现数据源切换
使用ThreadLocal存储每个线程的数据源
package cn.huangyk.datasourceswitch.config;
/**
* @author huangyk
* @version 1.0
* @since 2019/7/20
*/
public class DBContextHolder {
private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();
public static void set(DBTypeEnum dbType) {
contextHolder.set(dbType);
}
public static DBTypeEnum get() {
return contextHolder.get();
}
}
实现AbstractRoutingDataSource类动态获取数据源类型
package cn.huangyk.datasourceswitch.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.lang.Nullable;
/**
* @author huangyk
* @version 1.0
* @since 2019/7/20
*/
public class RoutingDataSource extends AbstractRoutingDataSource {
@Nullable
@Override
protected Object determineCurrentLookupKey() {
return DBContextHolder.get();
}
}
3.数据源配置
MyBatis数据源配置
package cn.huangyk.datasourceswitch.config;
import org.springframework.beans.factory.annotation.Qualifier;
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;
import java.util.HashMap;
import java.util.Map;
/**
* @author huangyk
* @version 1.0
* @since 2019/7/20
*/
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.druid.mycat")
public DataSource mycatDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.druid.mysql")
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public DataSource routingDataSource(@Qualifier("mycatDataSource") DataSource mycatDataSource,
@Qualifier("mysqlDataSource") DataSource mysqlDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.MYSQL, mysqlDataSource);
targetDataSources.put(DBTypeEnum.MYCAT, mycatDataSource);
RoutingDataSource routingDataSource = new RoutingDataSource();
routingDataSource.setDefaultTargetDataSource(mysqlDataSource);
routingDataSource.setTargetDataSources(targetDataSources);
return routingDataSource;
}
}
使用AOP实现数据源切换
package cn.huangyk.datasourceswitch.config;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author huangyk
* @version 1.0
* @since 2019/7/20
*/
@Aspect
@Component
public class DataSourceAop {
/**
* 通过切面实现数据源的切换
* @param jp
*/
@Before("execution(* cn.huangyk.datasourceswitch.service.*.*(..))")
public void datasourceSwitch(JoinPoint jp) {
Class<?> clazz=jp.getTarget().getClass();
Method method=((MethodSignature)jp.getSignature()).getMethod();
if(method.isAnnotationPresent(DBType.class)){
//方法上注解DBType的优先级最高
DBContextHolder.set(method.getAnnotation(DBType.class).type());
}else if(clazz.isAnnotationPresent(DBType.class)){
//类上注解DBType的优先级第二
DBContextHolder.set(clazz.getAnnotation(DBType.class).type());
}else{
//没有注解DBType时的默认数据源
DBContextHolder.set(DBTypeEnum.MYSQL);
}
}
}
4.附录
pom.xml
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.scau.hangyk</groupId>
<artifactId>datasource-switch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>datasource-switch</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
properties.yml
server:
port: 8088
spring:
datasource:
druid:
mycat:
name: mycatdb
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:32066/mycatdb?useUnicode=true&characterEncoding=utf8
username: root
password: 12345
mysql:
name: mysqldb
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:31503/mysqldb?useUnicode=true&characterEncoding=utf8
username: root
password: 12345
debug: false
5.测试例子
以上!