springboot 项目中多数据源的配置
yml配置文件上进行多数据源的配置
#spring datasource
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql:/
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
thymeleaf:
prefix: classpath:/templates/pages/
suffix: .html
aop:
proxy-target-class: false
#从数据源
slave:
datasource:
names: ds1
ds1:
url: jdbc:mysql:/
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
继承数据源类
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceType();
}
}
自定义数据源处理类
public class DynamicDataSourceContextHolder {
private Logger logger = Logger.getLogger(DynamicDataSourceContextHolder.class);
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static List<String> dataSourceIds = new ArrayList<String>();
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clearDataSourceType() {
contextHolder.remove();
}
public static boolean isContainsDataSource(String dataSourceId) {
return dataSourceIds.contains(dataSourceId);
}
}
注册
public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware{
private Logger logger = Logger.getLogger(DynamicDataSourceRegister.class);
private static final String DATASOURCE_TYPE_DEFAULT = "com.alibaba.druid.pool.DruidDataSource";
private DataSource defaultDataSource;
private Map<String, DataSource> slaveDataSources = new HashMap<>();
@Override
public void setEnvironment(Environment environment) {
initDefaultDataSource(environment);
initslaveDataSources(environment);
}
private void initDefaultDataSource(Environment env) {
Map<String, Object> dsMap = new HashMap<>();
dsMap.put("driver", env.getProperty("spring.datasource.driver-class-name"));
dsMap.put("url", env.getProperty("spring.datasource.url"));
dsMap.put("username", env.getProperty("spring.datasource.username"));
dsMap.put("password", env.getProperty("spring.datasource.password"));
defaultDataSource = buildDataSource(dsMap);
}
private void initslaveDataSources(Environment env) {
String dsPrefixs = env.getProperty("slave.datasource.names");
for (String dsPrefix : dsPrefixs.split(",")) {
Map<String, Object> dsMap = new HashMap<>();
dsMap.put("driver", env.getProperty("slave.datasource." + dsPrefix + ".driver-class-name"));
dsMap.put("url", env.getProperty("slave.datasource." + dsPrefix + ".url"));
dsMap.put("username", env.getProperty("slave.datasource." + dsPrefix + ".username"));
dsMap.put("password", env.getProperty("slave.datasource." + dsPrefix + ".password"));
DataSource ds = buildDataSource(dsMap);
slaveDataSources.put(dsPrefix, ds);
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
targetDataSources.put("dataSource", this.defaultDataSource);
DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
targetDataSources.putAll(slaveDataSources);
for (String key : slaveDataSources.keySet()) {
DynamicDataSourceContextHolder.dataSourceIds.add(key);
}
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DynamicDataSource.class);
beanDefinition.setSynthetic(true);
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
mpv.addPropertyValue("targetDataSources", targetDataSources);
beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
logger.info("Dynamic DataSource Registry");
}
public DataSource buildDataSource(Map<String, Object> dataSourceMap) {
try {
Object type = dataSourceMap.get("type");
if (type == null) {
type = DATASOURCE_TYPE_DEFAULT;
}
Class<? extends DataSource> dataSourceType;
dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
String driverClassName = dataSourceMap.get("driver").toString();
String url = dataSourceMap.get("url").toString();
String username = dataSourceMap.get("username").toString();
String password = dataSourceMap.get("password").toString();
DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
.username(username).password(password).type(dataSourceType);
return factory.build();
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
切面
@Aspect
@Order(-1)
@Component
public class DynamicDattaSourceAspect {
private Logger logger = Logger.getLogger(DynamicDattaSourceAspect.class);
@Before("@annotation(targetDataSource)")
public void changeDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
String dbid = targetDataSource.name();
if (!DynamicDataSourceContextHolder.isContainsDataSource(dbid)) {
logger.error("数据源 " + dbid + " 不存在使用默认的数据源 -> " + joinPoint.getSignature());
} else {
logger.debug("使用数据源:" + dbid);
DynamicDataSourceContextHolder.setDataSourceType(dbid);
}
}
@After("@annotation(targetDataSource)")
public void clearDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
logger.debug("清除数据源 " + targetDataSource.name() + " !");
DynamicDataSourceContextHolder.clearDataSourceType();
}
}
注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
String name();
}
主启动类
@Import(DynamicDataSourceRegister.class)
目标方法
@TargetDataSource(name = "ds1")