博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring 配置多数据源 (可行)
阅读量:5903 次
发布时间:2019-06-19

本文共 5593 字,大约阅读时间需要 18 分钟。

可以看到AbstractRoutingDataSource获取数据源之前会先调用determineCurrentLookupKey方法查找当前的lookupKey,这个lookupKey就是数据源标识。

因此通过重写这个查找数据源标识的方法就可以让spring切换到指定的数据源了。
第一步:创建一个DynamicDataSource的类,继承AbstractRoutingDataSource并重写determineCurrentLookupKey方法,代码如下:

1 public class DynamicDataSource extends AbstractRoutingDataSource {2 3     @Override4     protected Object determineCurrentLookupKey() {5         // 从自定义的位置获取数据源标识6         return DynamicDataSourceHolder.getDataSource();7     }8 9 }

第二步:创建DynamicDataSourceHolder用于持有当前线程中使用的数据源标识,代码如下:

1 public class DynamicDataSourceHolder { 2     /** 3      * 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰 4      */ 5     private static final ThreadLocal
THREAD_DATA_SOURCE = new ThreadLocal
(); 6 7 public static String getDataSource() { 8 return THREAD_DATA_SOURCE.get(); 9 }10 11 public static void setDataSource(String dataSource) {12 THREAD_DATA_SOURCE.set(dataSource);13 }14 15 public static void clearDataSource() {16 THREAD_DATA_SOURCE.remove();17 }18 19 }

第三步:配置多个数据源和第一步里创建的DynamicDataSource的bean,简化的配置如下:

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 23
24
25
26
27
28
29
30
31
32
33
34

到这里已经可以使用多数据源了,在操作数据库之前只要DynamicDataSourceHolder.setDataSource("dataSource2")即可切换到数据源2并对数据库db2进行操作了。

示例代码如下:

1 @Service 2 public class DataServiceImpl implements DataService { 3     @Autowired 4     private DataMapper dataMapper; 5  6     @Override 7     public List
> getList1() { 8 // 没有指定,则默认使用数据源1 9 return dataMapper.getList1();10 }11 12 @Override13 public List
> getList2() {14 // 指定切换到数据源215 DynamicDataSourceHolder.setDataSource("dataSource2");16 return dataMapper.getList2();17 }18 19 @Override20 public List
> getList3() {21 // 指定切换到数据源322 DynamicDataSourceHolder.setDataSource("dataSource3");23 return dataMapper.getList3();24 }25 }

--------------------------------------------------------------------------------------华丽的分割线--------------------------------------------------------------------------------------------------

但是问题来了,如果每次切换数据源时都调用DynamicDataSourceHolder.setDataSource("xxx")就显得十分繁琐了,而且代码量大了很容易会遗漏,后期维护起来也比较麻烦。能不能直接通过注解的方式指定需要访问的数据源呢,比如在dao层使用@DataSource("xxx")就指定访问数据源xxx?当然可以!前提是,再加一点额外的配置^_^。

首先,我们得定义一个名为DataSource的注解,代码如下:

1 @Target({ TYPE, METHOD })2 @Retention(RUNTIME)3 public @interface DataSource {4     String value();5 }

然后,定义AOP切面以便拦截所有带有注解@DataSource的方法,取出注解的值作为数据源标识放到DynamicDataSourceHolder的线程变量中:

1 public class DataSourceAspect { 2  3     /** 4      * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源 5      *  6      * @param point 7      * @throws Exception 8      */ 9     public void intercept(JoinPoint point) throws Exception {10         Class
target = point.getTarget().getClass();11 MethodSignature signature = (MethodSignature) point.getSignature();12 // 默认使用目标类型的注解,如果没有则使用其实现接口的注解13 for (Class
clazz : target.getInterfaces()) {14 resolveDataSource(clazz, signature.getMethod());15 }16 resolveDataSource(target, signature.getMethod());17 }18 19 /**20 * 提取目标对象方法注解和类型注解中的数据源标识21 * 22 * @param clazz23 * @param method24 */25 private void resolveDataSource(Class
clazz, Method method) {26 try {27 Class
[] types = method.getParameterTypes();28 // 默认使用类型注解29 if (clazz.isAnnotationPresent(DataSource.class)) {30 DataSource source = clazz.getAnnotation(DataSource.class);31 DynamicDataSourceHolder.setDataSource(source.value());32 }33 // 方法注解可以覆盖类型注解34 Method m = clazz.getMethod(method.getName(), types);35 if (m != null && m.isAnnotationPresent(DataSource.class)) {36 DataSource source = m.getAnnotation(DataSource.class);37 DynamicDataSourceHolder.setDataSource(source.value());38 }39 } catch (Exception e) {40 System.out.println(clazz + ":" + e.getMessage());41 }42 }43 44 }

最后在spring配置文件中配置拦截规则就可以了,比如拦截service层或者dao层的所有方法:

1 
2
3
4
5
6
7
8

OK,这样就可以直接在类或者方法上使用注解@DataSource来指定数据源,不需要每次都手动设置了。

示例代码如下:

1 @Service 2 // 默认DataServiceImpl下的所有方法均访问数据源1 3 @DataSource("dataSource1") 4 public class DataServiceImpl implements DataService { 5     @Autowired 6     private DataMapper dataMapper; 7  8     @Override 9     public List
> getList1() {10 // 不指定,则默认使用数据源111 return dataMapper.getList1();12 }13 14 @Override15 // 覆盖类上指定的,使用数据源216 @DataSource("dataSource2")17 public List
> getList2() {18 return dataMapper.getList2();19 }20 21 @Override22 // 覆盖类上指定的,使用数据源323 @DataSource("dataSource3")24 public List
> getList3() {25 return dataMapper.getList3();26 }27 }

提示:注解@DataSource既可以加在方法上,也可以加在接口或者接口的实现类上,优先级别:方法>实现类>接口。也就是说如果接口、接口实现类以及方法上分别加了@DataSource注解来指定数据源,则优先以方法上指定的为准。

转载地址:http://ehkpx.baihongyu.com/

你可能感兴趣的文章
Xcode执行Analyze静态分析
查看>>
java基础第八天_多线程
查看>>
【MySQL】常用拼接语句
查看>>
树形菜单的存储设计
查看>>
设备上报数据规则流转FC推送钉钉群
查看>>
蓝鸥零基础学习HTML5第四讲 CSS的基础样式
查看>>
如何清理windows server 2008 R2 中winsxs文件夹
查看>>
聊聊LettucePoolingConnectionProvider
查看>>
对象内List数组为空处理成长度为0的list
查看>>
docker网络-2
查看>>
GitHub 上需要关注的 10 大 React 库
查看>>
重新开始写文章了~
查看>>
移动硬盘显示磁盘未被格式化要怎样办啊
查看>>
Kali下Metasploit的shellcode在windows中的使用
查看>>
RestFul服务介绍
查看>>
JEECG支付服务窗专题 - 激活开发者模式
查看>>
微信云控源码帮您快速复制营销
查看>>
Java 类与对象
查看>>
根据业务量弹性使用云资源
查看>>
linux 命令学习记录
查看>>