spring boot · 2022-12-31 0

SpringBoot 配置多数据源

1.maven 依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>

    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.5.0</version>
    </dependency>
</dependencies>

2.配置文件

spring:
  datasource:
    mysql:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/temp
      username: root
      password: 123456
    postgres:
      driver-class-name: org.postgresql.Driver
      jdbc-url: jdbc:postgresql://localhost:5432/postgres
      username: postgres
      password: 123456

3.配置类

@Configuration(proxyBeanMethods = false)
public class DataSourceConfig {

    @Bean("dataSourceMysql")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.mysql")
    public DataSource dataSourceMysql() {
        return DataSourceBuilder.create().build();
    }

    @Bean("dataSourcePostgres")
    @ConfigurationProperties(prefix = "spring.datasource.postgres")
    public DataSource dataSourcePostgres() {
        return DataSourceBuilder.create().build();
    }
}

4.使用 DataSource

@Component
public class QueryApplicationRunner implements ApplicationRunner {

    @Autowired
    private DataSource dataSource1;

    @Autowired
    @Qualifier("dataSourceMysql")
    private DataSource dataSource2;

    @Autowired
    @Qualifier("dataSourcePostgres")
    private DataSource dataSource3;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<Map<String, String>> select1 = select(dataSource1);
        List<Map<String, String>> select2 = select(dataSource2);
        List<Map<String, String>> select3 = select(dataSource3);

        System.out.println(select1);
        System.out.println(select2);
        System.out.println(select3);
    }

    private List<Map<String, String>> select(DataSource dataSource) throws SQLException {
        Connection connection = dataSource.getConnection();

        PreparedStatement statement = connection.prepareStatement("SELECT * FROM student_tbl");
        ResultSet resultSet = statement.executeQuery();

        List<Map<String, String>> list = new ArrayList<>();
        while (resultSet.next()){
            String id = resultSet.getString(1);
            String name = resultSet.getString(2);

            Map<String, String> map = new HashMap<>();
            map.put("id", id);
            map.put("name", name);
            list.add(map);
        }

        resultSet.close();
        statement.close();
        connection.close();

        return list;
    }
}
@SpringBootApplication
public class Boot {

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

结果:

[{name=mysql_1, id=1}]
[{name=mysql_1, id=1}]
[{name=pg_2, id=2}]

5.默认配置原理

application.yml 中的 spring.datasource 配置,对应 DataSourceProperties 配置类

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/temp
    username: root
    password: 123456
// DataSourceProperties.java
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
    ...
    private String driverClassName;

    private String url;

    private String username;

    private String password;
    ...
}

DataSourceAutoConfiguration 有注册 DataSourceProperties,注册 DataSourceConfiguration.Hikari

// DataSourceAutoConfiguration.java
...
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
    ...
    @Configuration(proxyBeanMethods = false)
    @Conditional(PooledDataSourceCondition.class)
    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
            DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
            DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
    protected static class PooledDataSourceConfiguration {

    }
    ...
}

DataSourceConfiguration 注册 HikariDataSource

// DataSourceConfiguration.java
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(HikariDataSource.class)
    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
            matchIfMissing = true)
    static class Hikari {

        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.hikari")
        HikariDataSource dataSource(DataSourceProperties properties) {
            HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
            if (StringUtils.hasText(properties.getName())) {
                dataSource.setPoolName(properties.getName());
            }
            return dataSource;
        }

    }

spring.factories 有 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

# spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\

JdbcTemplateConfiguration 会注册 JdbcTemplate

// JdbcTemplateConfiguration.java
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {

    @Bean
    @Primary
    JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        JdbcProperties.Template template = properties.getTemplate();
        jdbcTemplate.setFetchSize(template.getFetchSize());
        jdbcTemplate.setMaxRows(template.getMaxRows());
        if (template.getQueryTimeout() != null) {
            jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
        }
        return jdbcTemplate;
    }

}