详解AbstractRoutingDataSource(动态数据源切换)实现原理

JAVA herman 785浏览 0评论
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

数据库读写分离,动态数据源切换已成为大型网站的标配。因此结合本文我们一起来搞定动态数据源切换的原理。

说到原理,就必须要说到源码,说到源码就必须要从我们最初的设计说起。

多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个spring和hibernate的框架的项目中,我们在spring配置中往往是配置一个dataSource来连接数据库,然后绑定给sessionFactory,在dao层代码中再指定sessionFactory来进行数据库操作。

单数据源dataSource结构

上图是单数据源dataSource结构。但是上图的缺点太明显了,不支持多个数据源,于是我们再改进一下,让它支持多数据源。

多数据源结构

这种结构实现了多数据源,但是缺点也很明显啊,具有多个SessionFactory,不具有灵活性,而且太笨重了。如果再加一个数据源,就需要再加一个SessionFactory。

SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的。

顾名思义,SessionFactory,就是用来创建session会话(具体接下来讲)的工厂。如果存在多个Sessionfactory 那么Session是不是就乱套了,因此这种架构不可取。那么下面这种架构就应用而生。

单SessionFactory多数据源架构

看看上图,是不是感觉合理了很多。Spring的AbstractRoutingDataSource就是采用这种架构。

看到这里你应该就明白了 AbstractRoutingDataSource 的原理。如果你还不明白,没关系,我们接着往下看。

看看 AbstractRoutingDataSource 的设计源码吧!

public abstract class AbstractRoutingDataSource 
	extends AbstractDataSource 
	implements InitializingBean

扩展Spring的AbstractRoutingDataSource抽象类(该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。)

从上可以看出它继承了AbstractDataSource,而AbstractDataSource不就是javax.sql.DataSource的子类吗,So我们可以分析下它的getConnection方法:

public Connection getConnection() throws SQLException {  
    return determineTargetDataSource().getConnection();  
}  
public Connection getConnection(String username, String password) throws SQLException {  
     return determineTargetDataSource().getConnection(username, password);  
}

获取连接的方法中,重点是determineTargetDataSource()方法,看源码:

protected DataSource determineTargetDataSource() {  
	Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");  
	Object lookupKey = determineCurrentLookupKey();  
	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 + "]");  
	}  
	return dataSource;  
}

上面这段源码的重点在于determineCurrentLookupKey()方法,这是AbstractRoutingDataSource类中的一个抽象方法,而它的返回值是你所要用的数据源dataSource的key值,有了这个key值,resolvedDataSource(这是个map,由配置文件中设置好后存入的)就从中取出对应的DataSource,如果找不到,就用配置默认的数据源。

看完源码,应该有点启发了吧,没错!你要扩展AbstractRoutingDataSource类,并重写其中的determineCurrentLookupKey()方法,来实现数据源的切换:

package com.xttblog.database;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
 * 获取数据源(依赖于spring)
 * @author linhy
 */
public class DynamicDataSource extends AbstractRoutingDataSource{
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceHolder.getDataSource();
    }
}

至此我相信关于 AbstractRoutingDataSource 的原理你已经明白了。现在在结合我们前面的一个案例来回顾一下  AbstractRoutingDataSource 吧。附上前一篇文章:Spring动态路由AbstractRoutingDataSource(数据源动态切换)教程

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » 详解AbstractRoutingDataSource(动态数据源切换)实现原理