SpringBoot多数据源配置

    Springboot单个数据源比较容易配置,它自动装配特性支持下,DataSource的初始化和注入等比较便捷。但是在多数据源情况下,反而有些蹩脚;其实实施起来也不算太复杂,方式也比较多。本文展示一个比较易用的方式,仅供参考。

    我们假定有2个数据源,dataSource1和dataSource2,基于tomcat-jdbc连接池,粗略配置如下文所示,部分属性可以自行按需增加。

1、application.properties

################# dataSource ####################
datasource:
  default:
    url: jdbc:mysql://127.0.0.1:3306/test?autoReconnect=false
    username: root
    password: root
    maxActive: 32
    maxIdle: 4
    minIdle: 1
    defaultAutoCommit: true
    maxAge: 60000
    testOnBorrow: true
    testOnReturn: true
    validationQuery: SELECT 1
  db0:
    url: jdbc:mysql://127.0.0.1:3306/test0?autoReconnect=false
    username: root
    password: root
    maxActive: 32
    maxIdle: 4
    minIdle: 1
    defaultAutoCommit: true
    maxAge: 60000
    testOnBorrow: true
    testOnReturn: true
    validationQuery: SELECT 1
  db1:
    url: jdbc:mysql://127.0.0.1:3306/test1?autoReconnect=false
    username: root
    password: root
    maxActive: 32
    maxIdle: 4
    minIdle: 1
    defaultAutoCommit: true
    maxAge: 60000
    testOnBorrow: true
    testOnReturn: true
    validationQuery: SELECT 1

2、Application.java

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan("com.vipkid.sample.dao")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }


    @ConfigurationProperties(prefix = "datasource.default")
    @Bean("defaultDataSource")
    public DataSource defaultDataSource() {
        return DataSourceBuilder.create().build();
    }


    @ConfigurationProperties(prefix = "datasource.db0")
    @Bean(value = "dataSource0")
    public DataSource dataSource0() {
        return DataSourceBuilder.create().build();
    }

    @ConfigurationProperties(prefix = "datasource.db1")
    @Bean(value = "dataSource1")
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }

}

    原理比较简单,对于Spring容器而言,在Bean初始化之前(Spring Bean可以被export之前,并非Bean实例创建之前),可以执行已注册的“postProcessor”来完成一些特定操作。对于SpringBoot环境,如果@Bean被@ConfigurationProperties修饰,那么将会在Bean初始化之前通过"ConfigurationPropertiesBindingPostProcessor"执行一些属性设置操作:根据ConfigurationProperties.prefix通过匹配获得有效的properties列表,依次通过反射机制(内部有复杂的转换)获取同名property的setter方法并执行;最终目的就是将@ConfigurationProperties中限定的属性列表与@Bean实例同名属性进行赋值。

     以“defaultDataSource”为例:

     1)DataSource defaultDataSource()方法内部,就是尝试加载指定的一些dataSource类型,如classpath中存在则创建相应的DataSource实例。比如我们引入了tomcat-jdbc依赖,那么将会加载“org.apache.tomcat.jdbc.pool.DataSource”并创建其实例。当然你可以强制指定:

return DataSourceBuilder.create()
        .type(org.apache.tomcat.jdbc.pool.DataSource.class)
        .build();

    此方法返回dataSource实例,但是此实例并没有任何我们所需要的属性。即此时@ConfugurationProperties注释还没有发挥实际作用,只是@Bean部分执行完毕。

    2)根据Spring Bean原理,@Bean在export之前,需要执行一些postProcessor;那么在SpringBoot环境下,被@ConfigurationProperties修饰的Bean,需要执行ConfigurationPropertiesBindingPostProcessor,那么在yml中申明的属性才会被bind到DataSource实例中;比如“url”、“maxActive”等等。内部主要是PropertiesConfigurationFactory在发挥作用,将prefix传递给此Factory,此Factory将会从全局的properties列表中匹配符合prefix的属性列表(会准守springboot properties规范,比较将大写与“-”转化等),并对属性依次构建“DataSource”实例的setter方法(反射机制Method),然后执行。

    (源码参见,ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(Object bean,String beanName),其中bean为dataSource实例,beanName为“defaultDataSource”)

    3)此外,为了避免与SpringBoot默认的dataSource装配冲突,我们需要禁用内置的DataSourceAutoConfiguration:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

猜你喜欢

转载自shift-alt-ctrl.iteye.com/blog/2415086