动态切换数据源原理
有一种场景,调用ServiceA时,使用A数据源,调用ServiceB时,使用B数据源。在不改变原有代码的情况下,这个如何来实现呢。
下面是一种实现方式,供参考:
- 将各个数据源用key-value形式保存到map中,如下面这个类:
class RouteDatasource {
Map<String, Datasource> map = new HashMap<>();
map.push("goods", goodsDatasource);
map.push("order", orderDatasource);
获取Connection
public Connection getConnection() {
...
}
}
- 在操作某个Service类的时候选择对应的数据源
比如在操作com.project.service.goods.GoodsService.java时,key应该设置成goods。这里有个问题是,service类跟数据源是分开的,怎么样才能通知到
RouteDatasource类使用goods的key呢。
方法简单,使用ThreadLocal类,在使用GoodsService类时,ThreadLocal中放入key,然后RouteDatasource类从ThreadLocal中取。
class RouteDatasource {
Map<String, Datasource> map...
map.push("goods", goodsDatasource);
map.push("order", orderDatasource);
获取Connection
public Connection getConnection() {
String key = ThreadLocal.get();
Datasource ds = map.get(kay);
return ds.getConnection();
}
}
获取key完成了,如何设置key呢?不可能在每次使用前put一下吧。容易出错,代码也不美观。有一种方案是使用spring的AOP方式实现。
AOP可以在执行某个Service方法前做一些操作,那么我们就把设置key的操作放在AOP的before行为中。
大致思路是:判断当前方法所在类的package的名称来区分需要设置哪个key。
比如:com.project.service.goods.GoodsService.save()方法的package,是com.project.service.goods开头
那么AOP代码可以这样写
String methodInfo = ...
if(methodInfo.startWith("com.project.service.goods")) {
ThreadLocal.set("goods")
}
完整的代码如下:
@Component
@Aspect
public class DynamicDataSourceAspect {
@Before("execution(* com.project.service..*.*(..))")
public void before(JoinPoint jp) {
String methodName = jp.getSignature().getDeclaringTypeName();
if (StringUtils.isBlank(methodName)) {
return;
}
if (methodName.startsWith("com.project.service.goods")) {
ThreadLocal.set("goods")
} else if (methodName.startsWith("com.project.service.order")) {
ThreadLocal.set("order")
}
}
}
这样,以后只需要配置DynamicDataSourceAspect类即可。
总结
数据源动态切换,主要思想是通过事先定义好的Key-Value进行动态获取。主要使用了ThreadLocal和Spring AOP方式去串连起来。
spring为我们提供了数据源切换类org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,这个类的作用就是一开始提到的RouteDatasource类。感兴趣的同学可以看下代码,很简单。
本文介绍了一种在不修改原有代码情况下,实现根据调用不同Service动态切换数据源的方法。利用ThreadLocal和Spring AOP技术,通过判断Service类的包名来自动设置数据源key,实现了灵活的数据源管理。
1756

被折叠的 条评论
为什么被折叠?



