0


动态数据源-spring-AbstractRoutingDataSource

spring的动态数据源AbstractRoutingDataSource

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

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

1、实现效果

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

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

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

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

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

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

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

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

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

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

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

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

DataSource会绑定到SqlSessionFactoryBean的dataSource对象中

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

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

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

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

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

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

核心方法

afterPropertiesSet

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

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

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

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

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

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

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

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

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

6、扩展

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

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

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

标签: 数据库 java

本文转载自: https://blog.csdn.net/weixin_39937571/article/details/134600160
版权归原作者 飞行的小恐龙 所有, 如有侵权,请联系我们删除。

“动态数据源-spring-AbstractRoutingDataSource”的评论:

还没有评论