spring多数据源的配置

创建一个类 继承 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
重写方法 determineCurrentLookupKey

package com.sky.lp.util;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class ExtendsAbstractRoutingDataSource extends AbstractRoutingDataSource{//使用ThreadLocal 保证线程安全private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();public static void setDataSourceKey(String dataSource) {dataSourceKey.set(dataSource);}@Overrideprotected Object determineCurrentLookupKey() {return dataSourceKey.get();}
}

数据源配置

<!-- 定义数据源 使用 druid 包 --><bean id ="dataSource1" class= "com.alibaba.druid.pool.DruidDataSource" init-method= "init" destroy-method ="close"><property name ="name" value="druidOne" /><property name ="url" value= "jdbc:mysql://localhost:3306/littledemo" /><property name ="username" value="root" /><property name ="password" value= "laixu785^@#"></property ><property name ="driverClassName" value= "com.mysql.jdbc.Driver"></property ><property name ="initialSize" value="2" /><property name ="maxActive" value="10" /><property name ="minIdle" value="5" /><property name ="validationQuery" value= "SELECT COUNT(*) FROM DUAL" /><property name ="testWhileIdle" value="true" /><property name ="timeBetweenEvictionRunsMillis" value= "5000" /></bean ><!-- 定义数据源 使用 druid 包 --><bean id ="dataSource2" class= "com.alibaba.druid.pool.DruidDataSource" init-method= "init" destroy-method ="close"><property name ="name" value="druidTwo" /><property name ="url" value= "jdbc:mysql://localhost:3306/doubleo" /><property name ="username" value="root" /><property name ="password" value= "laixu785^@#"></property ><property name ="driverClassName" value= "com.mysql.jdbc.Driver"></property ><property name ="initialSize" value="2" /><property name ="maxActive" value="10" /><property name ="minIdle" value="5" /><property name ="validationQuery" value= "SELECT COUNT(*) FROM DUAL" /><property name ="testWhileIdle" value="true" /><property name ="timeBetweenEvictionRunsMillis" value= "5000" /></bean ><!-- 多数据源 --><bean id ="extendsAbstractRoutingDataSource" class= "com.sky.lp.util.ExtendsAbstractRoutingDataSource" >
<!-- 默认数据源 --><property name ="defaultTargetDataSource" ref= "dataSource2"/>
<!--    不用的数据源对应不用的key值 --><property name ="targetDataSources"><map ><entry key ="dataSource1" value-ref= "dataSource1"/><entry key ="dataSource2" value-ref= "dataSource2"/></map ></property ></bean >spring jdbcTemplate 数据源的使用,
<bean id= "jdbcTemplate" class= "org.springframework.jdbc.core.JdbcTemplate" ><property name ="dataSource" ref= "extendsAbstractRoutingDataSource" />
</bean >

注意:
spring集成 ibatis 或者是 hibernate 或者其他的 ORM 框架,使用的数据源都是,extendsAbstractRoutingDataSource。

测试代码

public static void main(String[] args) {
ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-servlet.xml");ExtendsAbstractRoutingDataSource myDataSource = appCtx.getBean("extendsAbstractRoutingDataSource", ExtendsAbstractRoutingDataSource.class);myDataSource.setDataSourceKey("dataSource1");JdbcTemplate jdbc = appCtx.getBean("jdbcTemplate", JdbcTemplate.class);List<?> list = jdbc.queryForList("select * from user");System.out.println(list);
}

spring多数据源工作原理(即多个数据源到底应该选择哪一下)

原理分析(这里以 spring 的 JdbcTemplate 为例子)
JdbcTemplate 中执行sql语句,是从 dataSource 中获取 数据库 Connection,通过Connection 执行sql 语句。
那么Connection是怎么获取到的呢,是通过
org.springframework.util.Assert.DataSourceUtils.getConnection(getDataSource()) 获取Connection的。

方法 getDataSource() 源码

public DataSource getDataSource() {return dataSource;
}

返回的dataSource,即配置 jdbcTemplate bean 的属性dataSource<property name ="dataSource" ref= "extendsAbstractRoutingDataSource" />
看一下org.springframework.util.Assert.DataSourceUtils.getConnection(getDataSource()) 的源码

public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {try {return doGetConnection(dataSource);} catch (SQLException ex) {throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);}
}public static Connection doGetConnection(DataSource dataSource) throws SQLException {Assert.notNull(dataSource, "No DataSource specified");ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction()))conHolder.requested();if (!conHolder.hasConnection())logger.debug("Fetching resumed JDBC Connection from DataSource");conHolder.setConnection(dataSource.getConnection());return conHolder.getConnection();logger.debug("Fetching JDBC Connection from DataSource");Connection con = dataSource.getConnection();if (TransactionSynchronizationManager.isSynchronizationActive())logger.debug("Registering transaction synchronization for JDBC Connection");ConnectionHolder holderToUse = conHolder;if (holderToUse == null)holderToUse = new ConnectionHolder(con);elseholderToUse.setConnection(con);holderToUse.requested();TransactionSynchronizationManager.registerSynchronization( new ConnectionSynchronization(holderToUse, dataSource));holderToUse.setSynchronizedWithTransaction( true);if (holderToUse != conHolder)TransactionSynchronizationManager.bindResource(dataSource, holderToUse);return con;
}

解读上面的代码,最终的目的就是要从dataSource中获取数据库的Connection。而获取数据库的Connection必须调用dataSource的getConnection。
(即 javax.sql.DataSource的接口规定 getConnection() 方法 )。
所以,可以在从dataSource获取Connection的过程中做手脚。这就是
org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource 做的工作。
AbstractRoutingDataSource 继承 org.springframework.jdbc.datasource.AbstractDataSource,AbstractDataSource 实现 javax.sql.DataSource 接口。

下面看一下 AbstractRoutingDataSource 的方法 getConnection 的源码

public Connection getConnection() throws SQLException {return determineTargetDataSource().getConnection();
}protected DataSource determineTargetDataSource() {Assert.notNull(resolvedDataSources, "DataSource router not initialized");Object lookupKey = determineCurrentLookupKey();DataSource dataSource = (DataSource)resolvedDataSources.get(lookupKey);if(dataSource == null && (lenientFallback || lookupKey == null))dataSource = resolvedDefaultDataSource;if(dataSource == null)throw new IllegalStateException((new StringBuilder()).append("Cannot determine target DataSource for lookup key [").append(lookupKey).append("]").toString());return dataSource;
}

注意 源码中的方法 determineCurrentLookupKey(),我们自己定义的类 ExtendsAbstractRoutingDataSource 重写了 AbstractRoutingDataSource 中的 determineCurrentLookupKey 方法。

到这里大家应该明白了,spring的动态数据库切换是怎么实现的了。至于其他的地方,大家有不明白的就看看源码。

spring多数据源的配置-以及原理相关推荐

  1. 深入理解Spring Boot数据源与连接池原理

    ​ Create by yster@foxmail.com 2018-8-2 一:开始 在使用Spring Boot数据源之前,我们一般会导入相关依赖.其中数据源核心依赖就是spring‐boot‐s ...

  2. Spring Boot的自动配置的原理

    Spring Boot在进行SpringApplication对象实例化时会加载META-INF/spring.factories文件,将该配置文件中的配置载入到Spring容器. 1.1   Mav ...

  3. [Spring Boot] 4. Spring Boot实现自动配置的原理

    入口注解类@EnableAutoConfiguration @SpringBootApplication注解中包含了自动配置的入口注解: @Target(ElementType.TYPE) @Rete ...

  4. Spring, MyBatis 多数据源的配置和管理

    同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还 ...

  5. Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件

    本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...

  6. SpringBoot (八) :Spring Boot多数据源(JdbcTemplate)配置与使用

    什么是JdbcTemplate 为了使 JDBC 更加易于使用,Spring 在 JDBCAPI 上定义了一个抽象层, 以此建立一个JDBC存取框架. 作为 SpringJDBC 框架的核心, JDB ...

  7. Spring多数据源配置和使用

    Spring多数据源配置和使用 1.配置信息 <!--==============================bpt_mobdb数据库配置========================== ...

  8. spring(16)------spring的数据源配置

    spring(16)------spring的数据源配置 在spring中,通过XML的形式实现数据源的注入有三种形式. 一.使用spring自带的DriverManagerDataSource 使用 ...

  9. 搭建eclipse版的ssm+maven+tk.mybatis+redis及mybatis+spring多数据源配置集成的demo

    前言:我这里搭建好eclipse版的ssm+maven+tk.mybatis+redis及mybatis+spring多数据源配置集成的demo.新手快速上手直接看demo. 最后处提供完整高质量de ...

最新文章

  1. Spring MVC原理
  2. 华为视觉研究路线图:三大挑战,六项计划
  3. 如何在C++中动态建立二维数组
  4. 【网络流】 HDU 4183 Pahom on Water 拆点
  5. 转:[置顶] 从头到尾彻底理解KMP(2014年8月22日版)
  6. java集合的批量新建_java使用Arrays.asList快速创建List集合
  7. Tomcat虚拟目录的配置
  8. sap.ca.scfld.md.Startup.init('cus.crm.notes', this);
  9. 建立SQL Server警告和给操作员发送email通知
  10. CSS 文本缩进text-indent属性
  11. 经典算法题--求对策字符串的最大长度
  12. 安装nodejs插件并在sublime text 3上使用
  13. bzoj5138 [Usaco2017 Dec]Push a Box
  14. 解决Postman报错Could not send request
  15. 腾讯 IVWEB 团队:前端识别验证码思路分析
  16. 螺旋图形Linux,一个实例带你熟练使用UG中的螺旋线,新手必备!
  17. Android拦截黑名单(简易版)
  18. 克服低温磁场测量的挑战—高斯计
  19. checkra1n越狱错误79_苹果越狱工具 checkra1n 更新:支持 iOS 13.4.1
  20. html网页里如何竖着打字,搜狗输入法怎么设置为竖排显示 怎样把横向打字变成竖向...

热门文章

  1. 什么是 BeanDefinition?
  2. win7无法打开共享文件夹的文件
  3. 使用PXI设备做IC的开短路测试
  4. 黑衣人---走出软件作坊:三五个人十来条枪 如何成为开发正规军(三十四)
  5. R分数复现 R-precision评估指标定量 文本生成图像R分数定量实验全流程复现(R-precision)定量评价实验踩坑避坑流程
  6. telnet对应的端口不通,防火墙关闭了也不行
  7. java内部模型,13 张图拆解 Java 中的内存模型
  8. python 实现文件的批量压缩为.zip格式+.zip格式文件的解析
  9. 本机IP地址,ios的IP地址,www.ip138.com,
  10. 梦里Babel知多少(一)