下面一个Java类是已经写好的根据配置文件动态创建多dataSource的代码,其原理也很简单,就是读取配置文件,根据配置文件中配置的数据源数量,动态创建dataSource并注册到Spring中。

代码如下:

package org.springboot.sample.config;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry; import javax.sql.DataSource; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.AnnotationScopeMetadataResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ScopeMetadata;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.core.env.Environment; /**
* 动态创建多数据源注册到Spring中
*
*/
@Configuration
public class MultipleDataSourceBeanDefinitionRegistryPostProcessor
implements BeanDefinitionRegistryPostProcessor, EnvironmentAware { private static final Logger logger = LoggerFactory
.getLogger(MultipleDataSourceBeanDefinitionRegistryPostProcessor.class); // 如配置文件中未指定数据源类型,使用该默认值
private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";
// private static final Object DATASOURCE_TYPE_DEFAULT = "com.zaxxer.hikari.HikariDataSource"; private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); // 存放DataSource配置的集合,模型<dataSourceName,dataSourceMap>
private Map<String, Map<String, Object>> dataSourceMap = new HashMap<>(); @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
logger.info("Invoke Metho postProcessBeanFactory");
beanFactory.getBeanDefinition("dataSource").setPrimary(true); BeanDefinition bd = null;
Map<String, Object> dsMap = null;
for (Entry<String, Map<String, Object>> entry : dataSourceMap.entrySet()) {
bd = beanFactory.getBeanDefinition(entry.getKey());
MutablePropertyValues mpv = bd.getPropertyValues();
dsMap = entry.getValue();
mpv.addPropertyValue("driverClassName", dsMap.get("url"));
mpv.addPropertyValue("url", dsMap.get("url"));
mpv.addPropertyValue("username", dsMap.get("username"));
mpv.addPropertyValue("password", dsMap.get("password"));
}
} @SuppressWarnings("unchecked")
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
logger.info("Invoke Metho postProcessBeanDefinitionRegistry"); try {
if(!dataSourceMap.isEmpty()){
for (Entry<String, Map<String, Object>> entry : dataSourceMap.entrySet()) { Object type = entry.getValue().get("type");
if(type == null)
type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
registerBean(registry, entry.getKey(), (Class<? extends DataSource>)Class.forName(type.toString()));
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} } /**
* 注册Bean到Spring
*
* @param registry
* @param name
* @param beanClass
*/
private void registerBean(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 可以自动生成name
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
} /**
* 加载多数据源配置
*/
@Override
public void setEnvironment(Environment env) {
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "custom.datasource.");
String dsPrefixs = propertyResolver.getProperty("names");
for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
dataSourceMap.put(dsPrefix, dsMap);
}
}
}

将该Java文件直接添加到项目中便可,无其他任何代码耦合,就是单纯一个类。


再来看一下在配置文件中配置多数据源的方法:

# 主数据源,默认的
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456 # 更多数据源
custom.datasource.names=ds1,ds2,ds3
custom.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds1.url=jdbc:mysql://localhost:3306/test
custom.datasource.ds1.username=root
custom.datasource.ds1.password=123456 custom.datasource.ds2.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds2.url=jdbc:mysql://localhost:3306/test
custom.datasource.ds2.username=root
custom.datasource.ds2.password=123456 custom.datasource.ds3.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.ds3.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds3.url=jdbc:mysql://localhost:3306/test
custom.datasource.ds3.username=root
custom.datasource.ds3.password=123456 # 下面为连接池的补充设置,应用到上面所有数据源中
spring.datasource.maximum-pool-size=100
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
spring.datasource.validation-query=SELECT 1
spring.datasource.test-on-borrow=false
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=18800

配置文件包括1个主数据源和多个数据源,其中主数据源在Spring中的beanName默认为dataSource,另外几个数据源的beanName分包为:ds1、ds2、ds3,大家看一下配置的规则,想必不用多说。 
其中datasource的type属性可以具体指定到我们需要的数据源上面,不指定情况下默认为:org.apache.tomcat.jdbc.pool.DataSource

当然你也可以把这些数据源配置到主dataSource数据库中,然后读取数据库生成多数据源。当然这样做的必要性并不大,难不成数据源还会经常变吗。


在需要应用dataSource的地方需要指定名称,如:

// 方法参数注入方式
public void testDataSource(@Qualifier("ds1") DataSource myDataSource, @Qualifier("dataSource") DataSource dataSource) { }

或者

// 类成员属性注入方式
@Autowired
@Qualifier("ds1")
private DataSource dataSource1; @Resource(name = "ds2")
private DataSource dataSource2;

本文共享的代码可以直接使用了,大家可以根据自己需要进行调整。


然而我们在项目中不一定需要直接使用dataSource的,大家都习惯使用JDBC的jdbcTemplate、Mybatis的sqlSessionTemplate,再或者就是以Mybatis为例直接动态代理到Mapper接口上。

那么如何做到完全动态数据源呢,以至于实现我们可以为同一个Java类的不同方法,分别指定使用不同的数据源?

三、Spring Boot 多数据源配置的更多相关文章

  1. Spring Boot多数据源配置(二)MongoDB

    在Spring Boot多数据源配置(一)durid.mysql.jpa 整合中已经讲过了Spring Boot如何配置mysql多数据源.本篇文章讲一下Spring Boot如何配置mongoDB多 ...

  2. spring boot多数据源配置(mysql,redis,mongodb)实战

    使用Spring Boot Starter提升效率 虽然不同的starter实现起来各有差异,但是他们基本上都会使用到两个相同的内容:ConfigurationProperties和AutoConfi ...

  3. spring boot(12)-数据源配置原理

    本篇讲的不仅是数据源配置,这也是spring boot实现自动配置的一部分.要理解数据源的配置原理,首先要理解第十篇tomcat连接池的配置 数据源配置源码 这里截取org.springframewo ...

  4. Spring Boot Druid数据源配置

    package com.hgvip.config; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.su ...

  5. 21. Spring Boot Druid 数据源配置解析

    1.数据源配置属性类源码 package org.springframework.boot.autoconfigure.jdbc; @ConfigurationProperties( prefix = ...

  6. spring boot 多数据源配置与使用

    在介绍使用JdbcTemplate和Spring-data-jpa时,都使用了单数据源.在单数据源的情况下,Spring Boot的配置非常简单,只需要在application.properties文 ...

  7. Spring Boot多数据源配置与使用

    在单数据源的情况下,Spring Boot的配置非常简单,只需要在application.properties文件中配置连接参数即可.但是往往随着业务量发展,我们通常会进行数据库拆分或是引入其他数据库 ...

  8. Spring Boot (14) 数据源配置原理

    数据源配置源码 这里截取org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration的部分源码,主要介绍Tomcat和Hika ...

  9. Spring Boot多数据源配置(一)durid、mysql、jpa整合

    目前在做一个统计项目.需要多数据源整合,其中包括mysql和mongo.本节先讲mysql.durid.jpa与spring-boot的整合. 引入Durid包 <dependency> ...

随机推荐

  1. C#中抽象类与接口的区别

    1.面向接口编程和面向对象编程是什么关系 首先,面向接口编程和面向对象编程并不是平级的,它并不是比面向对象编程更先进的一种独立的编程思想,而是附属于面向对象思想体系,属于其一部分.或者说,它是面向对象 ...

  2. [转载] 详细讲解Hadoop中的简单数据库HBase

    转载自http://www.csdn.net/article/2010-11-28/282614 数据模型 HBase数据库使用了和Bigtable非常相似的数据模型.用户在表格里存储许多数据行.每个 ...

  3. STM32F4中USB与PC双向通信

    STM32F4系列处理器内部集成了USB-OTG控制器,在不要外部USB IC下就可以实现USB通信,最近两天看了下如何利用STM32的USB实现通信,记录下关键步骤: 1. 从http://www. ...

  4. Logger.getLogger和 LogFactory.getLog

    Logger.getLogger和 LogFactory.getLog Logger.getLogger LogFactory.getLogLogger来自log4j自己的包.如果用Logger.ge ...

  5. shopxx--权限功能测试

    shiro权限控制 一.添加角色 1.打开   系统→角色管理,点击 添加 赋予当前角色对应的权限 二.添加管理员(即用户管理) 添加用户,赋予刚才添加的角色 三.用新用户登录,进行测试 登录结果

  6. 软件测试管理QC

    一.QC简介 1)是HP公司的产品,是B/S结构的产品 2)在QC服务器中,打开IE浏览器,在地址栏中输入QC服务器的网址或者IP地址. 查看虚拟机的IP地址: 本地连接-属性-TCP/IP协议(重点 ...

  7. <meta http-equiv="X-UA-Compatible" content="IE=edge">的作用

    X-UA-Compatible是针对ie8新加的一个设置,对于ie8之外的浏览器是不识别的. X-UA-Compatible 是针对 IE8 版本的一个特殊文件头标记,用于为 IE8 指定不同的页面渲 ...

  8. 异常处理-try catch

    一:try catch是什么 try catch是java程序设计中处理异常的重要组成部分 异常是程序中的一些错误,有些异常需要做处理,有些则不需要捕获处理,异常是针对方法来说的,抛出.声明抛出.捕获 ...

  9. http高可用+负载均衡 corosync + pacemaker + pcs

    http高可用+负载均衡 corosync + pacemaker + pcsopenstack pike 部署 目录汇总 http://www.cnblogs.com/elvi/p/7613861. ...

  10. HDU 1317XYZZY spfa+判断正环+链式前向星(感觉不对,但能A)

    XYZZY Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...