多数据源切换详细讲解及其原理

Posted on 2019-12-20 11:33  嘿!!!!  阅读(6412)  评论(1编辑  收藏  举报

myBatis多数据源连接

1、首先得有一个Springmvc + Spring + Mybatis  maven项目

2、编辑一个扩展AbstractRoutingDataSource类,DynamicDataSource.java重写determineCurrentLookupKey()方法。

 

3 封装一个的对数据源进行操作的类,DbContextUtils.java

 

使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

从线程的角度看,目标变量就象是线程的本地变量,这也是类名中Local”所要表达的意思。

ThreadLocal的接口方法

ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

① void set(Object value)设置当前线程的线程局部变量的值。

② public Object get()该方法返回当前线程所对应的线程局部变量。

③ public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

④ protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null

4应用spring aop来设置,把配置的数据源类型都设置成为注解标签,在service层中需要切换数据源的方法上,写上注解标签,调用相应方法切换数据源.

4.1编辑注解标签TargetDataSource.java

 

注解说明

RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用

Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中

@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packagestypes(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标

4.2编辑切面的BeanAspectTargetDataSource.java

 

@Pointcut("@annotation(com.tynet.service.TargetDataSource)")

拦截带有@TargetDataSource注解的方法

@Before(value="setTargetDataSource() && @annotation(dataSource)")

前置任务中dataSource 指的是自定义切面注解上所附带的参数

 

5、配置配置文件

 

 

 

我这只显示两个,实际上可以连接很多数据源,只需要增加bean然后把id加入map中,我的默认的数据库是db_plat

6、记得声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。

 

7、方法上加上注解即可使用

 

8、实现原理

扩展SpringAbstractRoutingDataSource抽象类。

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

AbstractRoutingDataSource的源码:

 

它继承了AbstractDataSource,而AbstractDataSource正是javax.sql.DataSource的子类。

 

Java中数据库有很多连接方式,在众多方式中除了JDBC外都有DataSource对象。

DataSource可以看作数据源,它封装了数据库参数,连接数据库,程序中操作DataSource对象即可对数据库进行增删改查操作。

分析下AbstractRoutingDataSource实现DataSourcegetConnection方法:

 

看来重点是determineTargetDataSource()方法,上源码:

 

看注解,检索当前目标的数据源。

重点在于determineCurrentLookupKey()方法。

 

 

 

 

 

 

 

可以看到如果当前线程变量没有值,它首先被初始化为默认的值。

determineCurrentLookupKey()AbstractRoutingDataSource类中的一个抽象方法,而它的返回值是当前线程要用的数据源dataSourcekey值,有了这个key值,resolvedDataSource(这是个map,由配置文件中设置好后存入的)就从中取出对应的DataSource,如果找不到,就用配置默认的数据源。

而我们上面的所有操作都是要扩展AbstractRoutingDataSource类,并重写其中的determineCurrentLookupKey()方法,来实现数据源的切换。