在项目中经常会连接多个数据源,我结合了网上的一些示例和实际项目中的使用经验,做了些小小的改进,使配置更加简化了一下。先给出多数据源的配置:

spring:
  application:
    name: multiDatasource

  datasource:
    dbone:
      url: jdbc:mysql://172.17.10.150:3306/dbone?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456
    dbtwo:
      url: jdbc:mysql://172.17.10.150:3306/dbtwo?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456
    dbthree:
      url: jdbc:mysql://172.17.10.150:3306/dbthree?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456

    druid:
      driver-class-name: com.mysql.jdbc.Driver
      initial-size: 5
      max-active: 100
      min-idle: 5
      max-wait: 60000
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 30
      filters: stat

这里涉及到对druid的改造,默认druid是不支持这种形式的配置,这里把数据库连接的urlusernamepassword三个参数单独提取出来单独配置,其它配置项作为公共部分,查看了一下druid-spring-boot-starter的源码,它是通过DruidDataSourceWrapper配置类自动创建了一个数据源,它继承了DruidDataSource类,并实现了InitializingBean接口。由于不需要自己数据源的配置功能,所以不需要引用druid-spring-boot-starter包,我定了一个同名的DruidDataSourceWrapper类,稍进行改造了一下,去掉了@ConfigurationProperties("spring.datasource.druid")注解,将配置通过参数的形式传进来,手动创建数据源。主要代码如下:

public class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {

    private DruidConfig druidConfig;
    private DbConfig dbConfig;

    public DruidDataSourceWrapper(DbConfig dbConfig, DruidConfig druidConfig){
        this.dbConfig = dbConfig;
        this.druidConfig = druidConfig;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (super.getUsername() == null) {
            super.setUsername(dbConfig.getUsername());
        }
        if (super.getPassword() == null) {
            super.setPassword(dbConfig.getPassword());
        }
        if (super.getUrl() == null) {
            super.setUrl(dbConfig.getUrl());
        }
        if(druidConfig!=null){
            BeanUtils.copyProperties(druidConfig, this);
        }
    }

    @Autowired(required = false)
    public void autoAddFilters(List<Filter> filters){
        super.filters.addAll(filters);
    }

    /**
     * @since 1.1.14
     */
    @Override
    public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
        try {
            super.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
        } catch (IllegalArgumentException ignore) {
            super.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
        }
    }
}
@Setter
@Getter
@Component
@ConfigurationProperties(prefix = "spring.datasource.druid")
public class DruidConfig {
    private String driverClassName;
    private int initialSize = 5;
    private int maxActive = 100;
    private int minIdle = 5;
    private long maxWait = 60000;
    private long timeBetweenEvictionRunsMillis = 60000;
    private long minEvictableIdleTimeMillis = 300000;
    private String validationQuery = "SELECT 'x'";
    private boolean testWhileIdle = true;
    private boolean testOnBorrow = false;
    private boolean testOnReturn = false;
    private boolean poolPreparedStatements = true;
    private int maxPoolPreparedStatementPerConnectionSize = 30;
    private String filters = "stat";
}
@Setter
@Getter
public class DbConfig {

    private String url;
    private String username;
    private String password;
}

手动创建dbone数据源

@Configuration
@MapperScan(basePackages = {"cn.fetosoft.multi.data.dbone"},
        sqlSessionFactoryRef = "dboneSqlSessionFactory")
public class DboneDatasourceConfig {

    @Autowired
    private DruidConfig druidConfig;

    /**
     * 数据源配置
     * @return
     */
    @Bean(name = "dboneConfig")
    @ConfigurationProperties(prefix = "spring.datasource.dbone")
    public DbConfig buildDbConfig(){
        return new DbConfig();
    }

    /**
     * 系统数据源
     * @return
     */
    @Bean(name = "dboneDataSource")
    public DruidDataSource sysDataSource(@Qualifier("dboneConfig") DbConfig dbConfig){
        return new DruidDataSourceWrapper(dbConfig, druidConfig);
    }

    /**
     * 创建Mybatis的SqlSessionFactory
     * @return
     * @throws Exception
     */
    @Bean("dboneSqlSessionFactory")
    public SqlSessionFactory buildSqlSessionFactory(@Qualifier("dboneDataSource") DruidDataSource dataSource) throws Exception{
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        ResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(patternResolver.getResources("classpath:cn/fetosoft/multi/data/mapper/dbone/*.xml"));
        factoryBean.setConfigLocation(patternResolver.getResource("classpath:mybatis-config.xml"));
        return factoryBean.getObject();
    }
}
@Configuration
@MapperScan(basePackages = {"cn.fetosoft.multi.data.dbone"},
        sqlSessionFactoryRef = "dboneSqlSessionFactory")
public class DboneDatasourceConfig {

    @Autowired
    private DruidConfig druidConfig;

    /**
     * 数据源配置
     * @return
     */
    @Bean(name = "dboneConfig")
    @ConfigurationProperties(prefix = "spring.datasource.dbone")
    public DbConfig buildDbConfig(){
        return new DbConfig();
    }

    /**
     * 系统数据源
     * @return
     */
    @Bean(name = "dboneDataSource")
    public DruidDataSource sysDataSource(@Qualifier("dboneConfig") DbConfig dbConfig){
        return new DruidDataSourceWrapper(dbConfig, druidConfig);
    }

    /**
     * 创建SqlSessionFactory
     * @return
     * @throws Exception
     */
    @Bean("dboneSqlSessionFactory")
    public SqlSessionFactory buildSqlSessionFactory(@Qualifier("dboneDataSource") DruidDataSource dataSource) throws Exception{
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        ResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(patternResolver.getResources("classpath:cn/fetosoft/multi/data/mapper/dbone/*.xml"));
        factoryBean.setConfigLocation(patternResolver.getResource("classpath:mybatis-config.xml"));
        return factoryBean.getObject();
    }
}
``````java
@Configuration
@MapperScan(basePackages = {"cn.fetosoft.multi.data.dbone"},
        sqlSessionFactoryRef = "dboneSqlSessionFactory")
public class DboneDatasourceConfig {

    @Autowired
    private DruidConfig druidConfig;

    /**
     * 数据源配置
     * @return
     */
    @Bean(name = "dboneConfig")
    @ConfigurationProperties(prefix = "spring.datasource.dbone")
    public DbConfig buildDbConfig(){
        return new DbConfig();
    }

    /**
     * 系统数据源
     * @return
     */
    @Bean(name = "dboneDataSource")
    public DruidDataSource sysDataSource(@Qualifier("dboneConfig") DbConfig dbConfig){
        return new DruidDataSourceWrapper(dbConfig, druidConfig);
    }

    /**
     * 创建SqlSessionFactory
     * @return
     * @throws Exception
     */
    @Bean("dboneSqlSessionFactory")
    public SqlSessionFactory buildSqlSessionFactory(@Qualifier("dboneDataSource") DruidDataSource dataSource) throws Exception{
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        ResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(patternResolver.getResources("classpath:cn/fetosoft/multi/data/mapper/dbone/*.xml"));
        factoryBean.setConfigLocation(patternResolver.getResource("classpath:mybatis-config.xml"));
        return factoryBean.getObject();
    }
}

完整demo源码下载地址:https://github.com/gbinb/multi-datasource

发表评论