动态数据源-spring-AbstractRoutingDataSource

动态数据源-spring-AbstractRoutingDataSource

码农世界 2024-06-10 后端 112 次浏览 0个评论

spring的动态数据源AbstractRoutingDataSource

本质用的是多态和本地线程栈,适用于老项目动态切换数据源业务,单体服务

使用场景:SaaS服务部署,单服务多租户。当一个系统中需要多个数据库参与,我公司的业务是每个公司一个数据库,多个公司用同一个域名同一个网站,用的公司名(公司号)登录时

目录

1、实现效果

2、实现和继承关系

3、AbstractRoutingDataSource主体逻辑

4、项目使用的详细逻辑

​编辑

5、通过三个问题继续分析讲解其原理

5.1 如何影响正在执行mybatis执行sql语句的数据源选择?

5.2 如何初始化所有数据源?

5.3 线程执行时候如何选择正确的数据源?

6、扩展


1、实现效果

动态数据源-spring-AbstractRoutingDataSource

登录时候输入租户 用户名 密码

动态数据源-spring-AbstractRoutingDataSource

登录后显示具体租户信息,后续所有数据库操作都会去租户号的数据库查询

2、实现和继承关系

自定义DynamicDataSource类继承AbstractRoutingDataSource类

AbstractRoutingDataSource类继承了DataSource接口

3、AbstractRoutingDataSource主体逻辑

1、AbstractRoutingDataSource类持有多数据源map,默认数据源key。

2、web项目启动,bean初始化时会从配置文件中读取并转换获取数据源map,以及配置文件中读取的默认数据源key。

3、线程执行时,使用本地线程栈,通过拦截器或手动的方式存入数据源key,在后续sql执行时获取业务需要数据源key。

4、在运行sql时会调用父类getConnection()方法,此方法中会通过子类重写的determineCurrentLookupKey方法决定业务需要数据源key,再从数据源map中获取需要的数据源

注意:同一个线程可以运行,如果开新的线程都需要手动存入本地线程栈

4、项目使用的详细逻辑

1、DynamicDataSource动态数据源配置类的父类AbstractRoutingDataSource

动态数据源-spring-AbstractRoutingDataSource

2、AbstractRoutingDataSource的afterPropertiesSet方法,获取targetDataSources属性,由setTargetDataSources注入,在配置文件中指定,完成map初始化。

动态数据源-spring-AbstractRoutingDataSource

3、线程执行时,需求通过拦截器或手动的方式存入数据源key到本地线程栈

动态数据源-spring-AbstractRoutingDataSource

4、sql执行会调用DynamicDataSource父类getConnection方法,执行调用子类重写的determineTargetDataSource决定数据源key,子类会从本地线程栈中获业务指定数据源key(公司号)

动态数据源-spring-AbstractRoutingDataSource

动态数据源-spring-AbstractRoutingDataSource

动态数据源-spring-AbstractRoutingDataSource

ps:看明白的小伙伴后面可以不看略过了

5、通过三个问题继续分析讲解其原理

AbstractRoutingDataSource类如何影响正在执行mybatis执行sql语句的数据源选择?

AbstractRoutingDataSource类如何初始化所有数据源?

线程执行时候如何选择正确的数据源?

5.1 如何影响正在执行mybatis执行sql语句的数据源选择?

DataSource会绑定到SqlSessionFactoryBean的dataSource对象中

动态数据源-spring-AbstractRoutingDataSource

然后在每个sql执行时,调用dataSource接口的getConnection()方法获取数据库的连接,实际执行是会使用AbstractRoutingDataSource类的getConnection()选取指定数据的连接,这就是项目中每个执行sql可以使用AbstractRoutingDataSource类中指定数据源的原因。

那如何存储数据源和线程执行时选择正确的数据源呢?

5.2 如何初始化所有数据源?

AbstractRoutingDataSource类由配置文件注册到spring容器中

动态数据源-spring-AbstractRoutingDataSource

AbstractRoutingDataSource类本身有个四个核心属性

//用来通过配置文件指定所有的key值和value数据源
private Map targetDataSources;
//用来通过配置文件指定默认数据源
private Object defaultTargetDataSource;
//在afterPropertiesSet方法将defaultTargetDataSource中转为resolvedDefaultDataSource,这个是后面存储默认数据源
private DataSource resolvedDefaultDataSource;
//在afterPropertiesSet方法将targetDataSources中转为resolvedDataSources,这个是后面存储使用的名称-数据源映射
private Map resolvedDataSources;

核心方法

afterPropertiesSet

动态数据源-spring-AbstractRoutingDataSource

AbstractRoutingDataSource类实现了InitializingBean接口,所以此方法在这个bean初始化时执行afterPropertiesSet方法。afterPropertiesSet方法将配置文件中注入的targetDataSources和defaultTargetDataSource 转换为了后续可以使用的resolvedDefaultDataSource(默认数据源)和resolvedDataSources(存储使用的名称-数据源映射)

至此存储数据源完成,通过配置文件指定的方式,将默认数据源(没有指定数据源)和所有数据源存储的map初始化。剩下一个问题,选择正确的数据源呢?

5.3 线程执行时候如何选择正确的数据源?

在AbstractRoutingDataSource类的超类接口DataSource有核心方法getConnection,sql连接操作时会调用这个方法获取连接

动态数据源-spring-AbstractRoutingDataSource

这getConnection方法调用时的核心方法determineTargetDataSource

动态数据源-spring-AbstractRoutingDataSource

核心方法是determineCurrentLookupKey(),通过这个方法调用获取业务指定的的map中key值,获取resolvedDataSources中指定key的数据源,此处的key就是业务中指定的公司号

动态数据源-spring-AbstractRoutingDataSource

determineCurrentLookupKey()的实现在自定义的子类方法中

动态数据源-spring-AbstractRoutingDataSource

自定义的子类方法中,将key值业务定义使用的是本地线程栈技术

动态数据源-spring-AbstractRoutingDataSource

运用本地线程栈,可以在线程中手动或者自动(拦截器)将key值设定到本地线程栈对象contextHolder中,当sql执行时会,对调用AbstractRoutingDataSource的getConnection(),再调用determineTargetDataSource(),子类中determineCurrentLookupKey()最终决定了从本地线程栈对象contextHolder获取当前公司key字符串,用此公司key字符串在Map名称-数据源映射resolvedDataSources获取数据源

6、扩展

方法调用(接口调用)新增数据源/删除数据源

新增数据源,添加到map对象targetDataSources中,并重新执行afterPropertiesSet方法

动态数据源-spring-AbstractRoutingDataSource

删除数据源,DruidDataSourceStatManager类删除数据源对象,删除动态数据源map指定key并重新执行父类afterPropertiesSet方法

动态数据源-spring-AbstractRoutingDataSource

转载请注明来自码农世界,本文标题:《动态数据源-spring-AbstractRoutingDataSource》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,112人围观)参与讨论

还没有评论,来说两句吧...

Top