Spring Boot 多数据源配置

下面一个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类的不同方法,分别指定使用不同的数据源?

时间: 2024-10-07 19:35:42

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

spring boot 多数据源配置(多种数据库)

最近一段时间在使用spring boot开发项目,其中有一个项目用到了多数据源的配置,网上的资料还是不太多,走了好多才找到一个合适的,把自己写的分享一下,做个笔记,以后也许有用,第一次写博客,不好勿喷!! 首先介绍下我的业务场景,此项目用到了两种数据库,一个是mysql,另一个是sqlserver, 首先第一步需要在application.yml中将多数据源的配置信息进行配置, mysql数据源: spring: datasource: driverClassName: com.mysql.jd

Spring Boot多数据源配置与使用

有时候,一个系统的功能,需要两个或两个以上的数据库, 在Spring Boot 中要如何配置? How to? #primary primary.spring.datasource.jdbc-url=jdbc:mysql://localhost:3316/test1 primary.spring.datasource.username=root primary.spring.datasource.password=root primary.spring.datasource.driver-cla

spring boot多数据源配置示例

1. application.properties #\u4E3B\u5E93\u914D\u7F6E spring.datasource.primary.url=jdbc:mysql://mysql.test.xxxxx.com:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false spring.datasource.primary.username=root spring.datasource.primary.pas

Spring Boot? 多数据源配置(二):Spring-data-jpa

效果图: 代码区: package com.wls.integrateplugs.datasource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.Configuration

关于Spring Boot 多数据源的事务管理

自己的一些理解:自从用了Spring Boot 以来,这近乎零配置和“约定大于配置”的设计范式用着确实爽,其实对零配置的理解是:应该说可以是零配置可以跑一个简单的项目,因为Spring Boot 有默认的配置,当默认的配置满足不了你的时候,这时候所谓的零配置只是换了一种方式而已,我们都知道程序员最擅长的就是写代码,相比来说xml文件还是有点蛋疼的: 行啊,Spring Boot说你不是擅长写代码,那我就把配置给你转换为写代码的形式,所以你会发现在Spring Boot 中使用@Configura

Spring Boot 全局异常配置

Spring Boot 全局异常配置,处理异常控制器需要和发生异常的方法在一个类中.使用 ControllerAdvice 注解 package com.li.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ControllerAdvice; import

Spring Boot SSL [https]配置例子

前言 本文主要介绍Spring Boot HTTPS相关配置,基于自签证书实现: 通过本例子,同样可以了解创建SSL数字证书的过程: 本文概述 Spring boot HTTPS 配置 server.port=8443 server.ssl.key-alias=selfsigned_localhost_sslserver server.ssl.key-password=changeit server.ssl.key-store=classpath:ssl-server.jks server.ss

Spring Boot 外部化配置(二) - @ConfigurationProperties 、@EnableConfigurationProperties

目录 3.外部化配置的核心 3.2 @ConfigurationProperties 3.2.1 注册 Properties 配置类 3.2.2 绑定配置属性 3.1.3 ConfigurationPropertiesAutoConfiguration 4.总结 3.外部化配置的核心 ????????接着上一章,<Spring Boot 外部化配置(一)> 3.2 @ConfigurationProperties 众所周知,当 Spring Boot 集成外部组件后,就可在 propertie

Spring Boot + MyBatis + Pagehelper 配置多数据源

前言: 本文为springboot结合mybatis配置多数据源,在项目当中很多情况是使用主从数据源来读写分离,还有就是操作多库,本文介绍如何一个项目同时使用2个数据源. 也希望大家带着思考去学习!博主是最近才学的配置写成博文分享心得和技巧,文中有不足的欢迎留言指正,谢谢! 思考: 1.如果从传统的单数据源转换为多数据源,以前使用boot只用导包写配置文件boot会帮我们自动配置,如果不用自动配置我们改怎么配呢? 2.怎么结合mybatis分页插件一起使用呢? .................