前言:
????????本人使用的是springboot+mybatis-plus+阿里数据源+c3p0数据源,并将DruidDataSource进行密码加密,在代码中进行解密,连接数据库。
1.项目结构
2.代码
第一步pom.xml文件,引入jar包
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.fxr</groupId>
<artifactId>two_datasource</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>two_datasource</name>
<description>two_datasource</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.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>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
第二步配置数据源application.yml
spring:
datasource:
primary:
type: com.mchange.v2.c3p0.ComboPooledDataSource
driver-class-name: com.mysql.jdbc.Driver
username: root
password: "123456"
url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8&characterEncoding=UTF-8&useSSL=false
second:
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: XY4zMbnQC2e1iQi/+eA5r/hkrNF3Baxe3fGvk7y+0wBAyoEgtSUZh1JY102KoSmdgKaG62f0IXU5jmZaa0ONSQ==
# password: "123456"
url: jdbc:mysql://127.0.0.1:3306/nacos_config?serverTimezone=GMT%2B8&characterEncoding=UTF-8&useSSL=false
initial-size: 20
max-active: 50
min-idle: 5
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIbdVTp2Ct+ju/YwPkhNh9kwY+H83wXrSqFZ/stWKKVy9LA50ela1SgoDySxwstJWrLTcgaWB/sbMxa2pDoas3cCAwEAAQ==
# passwordCallbackClassName: com.fxr.learn_two_datasource.config.DbPasswordCallback
# connect-properties:
# config.decrypt: true
# config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIbdVTp2Ct+ju/YwPkhNh9kwY+H83wXrSqFZ/stWKKVy9LA50ela1SgoDySxwstJWrLTcgaWB/sbMxa2pDoas3cCAwEAAQ==
# filter:
# config:
# enabled: true
第三步 DynamicDataSourceConfig.class
import com.alibaba.druid.filter.config.ConfigTools;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.*.two_datasource.constants.DataSourceConstants;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.util.HashMap;
import java.util.Map;
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
@Configuration
@MapperScan(basePackages = "com.fxr.two_datasource.mapper")
public class DynamicDataSourceConfig {
@Value("${spring.datasource.second.password}")
private String password;
@Value("${spring.datasource.second.publicKey}")
private String publicKey;
@Bean(DataSourceConstants.DS_KEY_MASTER)
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DruidDataSource masterDataSource(){
return DruidDataSourceBuilder.create().build();
}
@Bean(DataSourceConstants.DS_KEY_SLAVE)
@ConfigurationProperties(prefix = "spring.datasource.second")
public DruidDataSource secondDataSource(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dynamicDataSource(){
Map<Object,Object> dataSourceMap=new HashMap<>(2);
DruidDataSource dataSource= secondDataSource();
String newpassword="";
try{
newpassword= ConfigTools.decrypt(publicKey, password);
System.out.println(newpassword);
}catch (Exception e){
e.printStackTrace();
}
dataSource.setPassword(newpassword);
dataSourceMap.put(DataSourceConstants.DS_KEY_MASTER,masterDataSource());
dataSourceMap.put(DataSourceConstants.DS_KEY_SLAVE,dataSource);
DynamicDataSource dynamicDataSource=new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
dynamicDataSource.setTargetDataSources(dataSourceMap);
return dynamicDataSource;
}
}
第四步?DynamicDataSource.class
import com.*.two_datasource.context.DynamicDataSourceContextHolder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getContextKey();
}
}
第五步?DataSourceConstants.class
public class DataSourceConstants {
public static final String DS_KEY_MASTER="primary";
public static final String DS_KEY_SLAVE = "second";
}
第六步? DynamicDataSourceContextHolder.class
public class DynamicDataSourceContextHolder {
/**
* 动态数据源名称上下文
*/
private static final ThreadLocal<String> DATASOURCE_CONTEXT_KEY_HOLDER = new ThreadLocal<>();
/**
* 设置数据源
* @param key
*/
public static void setContextKey(String key){
DATASOURCE_CONTEXT_KEY_HOLDER.set(key);
}
/**
* 获取数据源名称
* @return
*/
public static String getContextKey(){
String key = DATASOURCE_CONTEXT_KEY_HOLDER.get();
return key == null? DataSourceConstants.DS_KEY_MASTER:key;
}
/**
* 删除当前数据源名称
*/
public static void removeContextKey(){
DATASOURCE_CONTEXT_KEY_HOLDER.remove();
}
}
第七步?DynamicDataSourceAspect.class
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.springframework.stereotype.Component;
@Aspect
@Component
public class DynamicDataSourceAspect {
@Pointcut("@within(org.springframework.stereotype.Service)")
public void dataSourcePointCut(){}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature= (MethodSignature) joinPoint.getSignature();
Class<?> aClass=Class.forName(signature.getDeclaringType().getName());
if(signature.getMethod().isAnnotationPresent(DS.class)){
DynamicDataSourceContextHolder.setContextKey(signature.getMethod().getAnnotation(DS.class).value());
}else if(aClass.isAnnotationPresent(DS.class)){
DynamicDataSourceContextHolder.setContextKey(aClass.getAnnotation(DS.class).value());
}else{
DynamicDataSourceContextHolder.setContextKey(DataSourceConstants.DS_KEY_MASTER);
}
try{
return joinPoint.proceed();
}finally {
DynamicDataSourceContextHolder.removeContextKey();
}
}
}
第八步? DS.class
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
String value() default "primary";
}
第九步 业务
?
|