1.yml配置:
spring:
datasource:
his:
driver-class-name: com.mysql.cj.jdbc.Driver
password: aa
jdbc-url: jdbc:mysql://aa:3306/aa?useUnlcode=1&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&remarksReporting=true&serverTimezone=GMT%2B8
username: aa
gym:
driver-class-name: com.mysql.cj.jdbc.Driver
password: bb
jdbc-url: jdbc:mysql://bb/bb?useUnlcode=1&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&remarksReporting=true&serverTimezone=GMT%2B8
username: bb
package com.gymexpress.histar.config;
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 org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
2.多数据源配置类
/**
* @author
* 多数据源配置类
*/
@Configuration
public class DataSourceConfig {
/**
* 数据源exgym_new
* @return
*/
@Bean(name="dataSourceHis")
@ConfigurationProperties(prefix = "spring.datasource.his")
public DataSource dataSourceHis(){
return DataSourceBuilder.create().build();
}
/**
* 数据源gym
* @return
*/
@Bean(name="dataSourceGym")
@ConfigurationProperties(prefix = "spring.datasource.gym")
public DataSource dataSourceGym(){
return DataSourceBuilder.create().build();
}
/**
* 动态数据源:通过aop在不同的数据源之间动态切换
* @return
*/
@Primary
@Bean(name="dynamicDataSource")
public DataSource dynamicDataSource(){
DynamicDataSource dynamicDataSource=new DynamicDataSource();
//默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSourceHis());
//配置多数据源
Map<Object,Object> dsMap=new HashMap<>();
dsMap.put("dataSourceHis",dataSourceHis());
dsMap.put("dataSourceGym",dataSourceGym());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
/**
* 配置@transactional注解事务
* @return
*/
@Bean
public PlatformTransactionManager transactionManager(){
return new DataSourceTransactionManager(dynamicDataSource());
}
}
3.配置默认数据源
package com.gymexpress.histar.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DataSourceContextHolder {
private static final Logger LOGGER= LoggerFactory.getLogger(DataSourceContextHolder.class);
/**
* 默认数据源
*/
public static final String DEFAULT_DS="dataSourceHis";
/**
* 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
*/
private static final ThreadLocal<String> contextHolder=new ThreadLocal<>();
/**
* 设置数据库名
* @param dbType
*/
public static void setDB(String dbType){
LOGGER.info("切换到{"+dbType+"}数据源");
contextHolder.set(dbType);
}
/**
* 获取数据源名
* @return
*/
public static String getDB(){
return (contextHolder.get());
}
/**
* 清楚数据源
*/
public static void clearDB(){
contextHolder.remove();
}
}
4.自定义注解
package com.gymexpress.histar.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author
* 自定义注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DS {
/**
* 默认His数据库
* @return
*/
String value() default "dataSourceHis";
}
5.获取数据源
package com.gymexpress.histar.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @author
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final Logger LOGGER= LoggerFactory.getLogger(DynamicDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
LOGGER.info("数据源为:"+DataSourceContextHolder.getDB());
return DataSourceContextHolder.getDB();
}
}
6.切换数据源
package com.gymexpress.histar.config;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 自定义注解 + AOP的方式实现数据源动态切换。
* @author
*
*/
@Aspect
@Component
public class DynamicDataSourceAspect {
private static final Logger LOGGER= LoggerFactory.getLogger(DynamicDataSourceAspect.class);
@Before("@annotation(DS)")
public void beforeSwitchDS(JoinPoint point){
//获得当前访问的class
Class<?> className = point.getTarget().getClass();
//获得访问的方法名
String name = point.getSignature().getName();
//得到方法参数的类型
Class[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes();
String datasource = DataSourceContextHolder.DEFAULT_DS;
try {
//得到访问的方法对象
Method method = className.getMethod(name, parameterTypes);
//判断是否存在@DS注解
if(method.isAnnotationPresent(DS.class)){
DS annotation = method.getAnnotation(DS.class);
//取出注解中的数据源名
datasource = annotation.value();
}
}catch (Exception e){
LOGGER.error(e.toString(),e);
}
//切换数据源
DataSourceContextHolder.setDB(datasource);
}
@After("@annotation(DS)")
public void afterSwitchDs(JoinPoint joinPoint){
DataSourceContextHolder.clearDB();
}
}