Spring Boot 多数据源

来源:互联网 发布:php中final 编辑:程序博客网 时间:2024/05/20 07:37

上篇文章介绍了如何手工使用Java代码将对象注册到Spring中,为本文“多数据源”做了基础。

下面一个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中 * * @author 单红宇(365384722) * @myblog http://blog.csdn.net/catoop/ * @create 2016年1月22日 */@Configurationpublic 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     * @author SHANHY     * @create 2016年1月22日     */    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);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129

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


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

# 主数据源,默认的spring.datasource.type=com.zaxxer.hikari.HikariDataSourcespring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/testspring.datasource.username=rootspring.datasource.password=123456# 更多数据源custom.datasource.names=ds1,ds2,ds3custom.datasource.ds1.type=com.zaxxer.hikari.HikariDataSourcecustom.datasource.ds1.driver-class-name=com.mysql.jdbc.Drivercustom.datasource.ds1.url=jdbc:mysql://localhost:3306/testcustom.datasource.ds1.username=rootcustom.datasource.ds1.password=123456custom.datasource.ds2.type=com.zaxxer.hikari.HikariDataSourcecustom.datasource.ds2.driver-class-name=com.mysql.jdbc.Drivercustom.datasource.ds2.url=jdbc:mysql://localhost:3306/testcustom.datasource.ds2.username=rootcustom.datasource.ds2.password=123456custom.datasource.ds3.type=com.zaxxer.hikari.HikariDataSourcecustom.datasource.ds3.driver-class-name=com.mysql.jdbc.Drivercustom.datasource.ds3.url=jdbc:mysql://localhost:3306/testcustom.datasource.ds3.username=rootcustom.datasource.ds3.password=123456# 下面为连接池的补充设置,应用到上面所有数据源中spring.datasource.maximum-pool-size=100spring.datasource.max-idle=10spring.datasource.max-wait=10000spring.datasource.min-idle=5spring.datasource.initial-size=5spring.datasource.validation-query=SELECT 1spring.datasource.test-on-borrow=falsespring.datasource.test-while-idle=truespring.datasource.time-between-eviction-runs-millis=18800
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

配置文件包括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) {}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

或者

// 类成员属性注入方式@Autowired@Qualifier("ds1")private DataSource dataSource1;@Resource(name = "ds2")private DataSource dataSource2;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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


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

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

0 0
原创粉丝点击