简单介绍
实现数据源切换的功能就是自定义一个类扩展AbstractRoutingDataSource抽象类,其实相当于数据源的路由中介,可以实现在项目运行时。根据相应的key值切换到对应的DataSource上。
DynamicDataSource类
package com
.picc
.agricultural
.service
;
import org
.springframework
.jdbc
.datasource
.lookup
.AbstractRoutingDataSource
;
public class DynamicDataSource extends AbstractRoutingDataSource {
protected Object
determineCurrentLookupKey() {
return DataSourceHolder
.getDataSource();
}
}
DataSourceHolder 类
public class DataSourceHolder {
private final static ThreadLocal
<String> datasources
= new ThreadLocal<String>();
public static void setDatasources(String source
) {
datasources
.set(source
);
}
public static String
getDataSource() {
return datasources
.get();
}
public static void clearDataSources() {
datasources
.remove();
}
}
TargetDataSource类
@Target({ElementType
.METHOD
, ElementType
.TYPE
})
@Retention(RetentionPolicy
.RUNTIME
)
@Documented
public @
interface TargetDataSource {
public String
value() default "";
}
DataSourceConfig 类
@Component
@ConfigurationProperties(prefix
= "spring.datasource")
@Data
public class DataSourceConfig {
private List
<DataSourceModel> jdbc
;
public Map
<Object,Object> getDataSourceMap() {
Map
<Object, Object> map
= new HashMap<>();
if (jdbc
!= null
&& jdbc
.size()>0) {
for (int i
= 0; i
< jdbc
.size(); i
++) {
DruidDataSource druidDataSource
= new DruidDataSource();
druidDataSource
.setDriverClassName(jdbc
.get(i
).getDriverClassName());
druidDataSource
.setUrl(jdbc
.get(i
).getUrl());
druidDataSource
.setUsername(jdbc
.get(i
).getUsername());
druidDataSource
.setPassword(jdbc
.get(i
).getPassword());
druidDataSource
.setDefaultReadOnly(jdbc
.get(i
).isDefaultReadOnly());
map
.put(jdbc
.get(i
).getConnname(),druidDataSource
);
}
}
return map
;
}
@Bean
public DynamicDataSource
dynamicData() {
Map
<Object, Object> targetDataSources
= getDataSourceMap();
DynamicDataSource dynamicDataSource
= new DynamicDataSource();
dynamicDataSource
.setTargetDataSources(targetDataSources
);
dynamicDataSource
.setDefaultTargetDataSource(targetDataSources
.values().toArray()[0]);
return dynamicDataSource
;
}
@Bean
public SqlSessionFactory
sqlSessionFactory(DynamicDataSource dynamicData
) throws Exception
{
SqlSessionFactoryBean sqlSessionFactoryBean
= new SqlSessionFactoryBean();
sqlSessionFactoryBean
.setDataSource(dynamicData
);
return sqlSessionFactoryBean
.getObject();
}
}
DataSourceAspect 切面
@Component
@Aspect
public class DataSourceAspect {
@Before("@annotation(TargetDataSource)")
public void before(JoinPoint joinPoint
){
TargetDataSource annotation
= ((MethodSignature
) joinPoint
.getSignature()).getMethod().getAnnotation(TargetDataSource
.class);
DataSourceHolder
.setDatasources(annotation
.value());
}
@After("@annotation(TargetDataSource)")
public void after(){
DataSourceHolder
.clearDataSources();
}
}
使用的时候,将@TargetDataSource (‘DB1’)放在dao层方法上就可以
AbstractRoutingDataSource核心方法
protected DataSource
determineTargetDataSource() {
Assert
.notNull(this.resolvedDataSources
, "DataSource router not initialized");
Object lookupKey
= this.determineCurrentLookupKey();
DataSource dataSource
= (DataSource
)this.resolvedDataSources
.get(lookupKey
);
if (dataSource
== null
&& (this.lenientFallback
|| lookupKey
== null
)) {
dataSource
= this.resolvedDefaultDataSource
;
}
if (dataSource
== null
) {
throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey
+ "]");
} else {
return dataSource
;
}
}