在Spring Boot中以编程方式配置DataSource

91
使用Spring Boot,我可以使用以下代码实例化一个JdbcTemplate
代码:
@Autowired
private JdbcTemplate jdbcTemplate;

属性:
spring.datasource.url=jdbc:postgresql://my_url:my_port/my_other_stuff
spring.datasource.username=my_user_name
spring.datasource.password=my_password
spring.datasource.driver-class-name=org.postgresql.Driver

这将创建一个类为org.apache.tomcat.jdbc.pool.DataSource的数据源。
我如何以编程方式设置数据源的用户名/密码?
我们有一个不以明文形式存储凭据的策略,我必须在工作中使用特定的凭据提供程序。
8个回答

94

如果你使用jdbc启动器,可以使用DataSourceBuilder。此外,为了覆盖默认的自动配置bean,您需要将您的bean标记为@Primary

在我的情况下,我有以datasource.postgres前缀开头的属性。

例如:

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

如果对你来说不可行,那么你可以使用

@Bean
@Primary
public DataSource dataSource() {
    return DataSourceBuilder
        .create()
        .username("")
        .password("")
        .url("")
        .driverClassName("")
        .build();
}

8
@Primary并不是必须的,因为AutoConfiguration只会在没有其他bean被定义时创建一个DataSource bean。 - dunni
create() 应该放在最前面。 - Marsellus Wallace
根据JavaDoc @Primary,“表明当有多个候选项符合自动装配单个值依赖性时,应优先考虑给定的bean。” https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html - Andres Felipe
6
那么针对 spring.datasource.validation-queryspring.datasource.test-while-idlespring.datasource.time-between-eviction-runs-millis 这些配置怎么处理呢?请您指示。 - zhuguowei
我也有同样的问题 - 在多租户项目中如何设置“spring.datasource.validation-query”,其中我们使用DataSourceBuilder.create()在运行时创建DataSource。 - Vijay Shegokar
显示剩余3条评论

26

在您的帮助下,我的Spring Boot项目已经正常运行。Yaml数据源配置如下:

spring:
  # (DataSourceAutoConfiguration & DataSourceProperties)
  datasource:
    name: ds-h2
    url: jdbc:h2:D:/work/workspace/fdata;DATABASE_TO_UPPER=false
    username: h2
    password: h2
    driver-class: org.h2.Driver

自定义数据源

@Configuration
@Component
public class DataSourceBean {

    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    @Primary
    public DataSource getDataSource() {
        return DataSourceBuilder
                .create()
//                .url("jdbc:h2:D:/work/workspace/fork/gs-serving-web-content/initial/data/fdata;DATABASE_TO_UPPER=false")
//                .username("h2")
//                .password("h2")
//                .driverClassName("org.h2.Driver")
                .build();
    }
}

3
这个答案很有帮助,因为它展示了如何使用默认的spring.datasource属性来定义数据源。请注意,如果您只想覆盖密码,那么您需要从application.properties(或application.yml)中删除密码定义,并在代码中设置该属性。 - user41871
1
@Willie Wheeler 你确定这样会起作用吗?因为我理解上面的代码将返回一个全新的数据源bean。这意味着spring.datasource属性不会生效,并将被新bean替换。 - Fadhlie Ikram
1
是的,我已经使用了这种方法将密码外部化到Vault中。 - user41871
1
@WillieWheeler 你是对的。我刚试了一下,它可以工作。 - Fadhlie Ikram
很高兴听到这个消息 @FadhlieIkram。谢谢您的确认。 - user41871

16

你只需要在返回一个 DataSource 的方法上添加 @Bean 注解。

下面给出了一个完整的工作示例。

@Bean
public DataSource dataSource() {
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.url(dbUrl);
        dataSourceBuilder.username(username);
        dataSourceBuilder.password(password);
        return dataSourceBuilder.build();   
}

15

如果您正在使用最新的Spring Boot(带有JDBC Starter和Hikari),则会遇到以下问题:

java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.

为解决该问题,您需要执行以下操作:

  1. 在您的application.properties文件中添加以下内容:

datasource.oracle.url=youroracleurl

  1. 在您的应用程序中定义bean (@Primary是必需的!)
@Bean
@Primary
@ConfigurationProperties("datasource.oracle")
public DataSourceProperties getDatasourceProperties() {
    return new DataSourceProperties();
}

@Bean
@ConfigurationProperties("datasource.oracle")
public DataSource getDatasource() {
    return getDatasourceProperties().initializeDataSourceBuilder()
           .username("username")
           .password("password")
           .build();
}

我还必须将DataSource bean声明为@Primary。 - Nis
3
有一个更简单的方法:在应用程序属性文件中(即application.yml),将spring.datasource.url重命名为spring.datasource.jdbc-url。这样就行了!(我是用在SpringBoot v2.3.2上成功的) - Davide Martorana
@DavideMartorana 我觉得这个技巧不错,但我猜它不能与HikariConfig等类集成(所以需要修改代码来更新Hikari配置)。 - kodstark

5
如果您需要更多的数据源配置,比如:
spring.datasource.test-while-idle=true 
spring.datasource.time-between-eviction-runs-millis=30000
spring.datasource.validation-query=select 1

您可以使用以下代码。
@Bean
public DataSource dataSource() {
    DataSource dataSource = new DataSource(); // org.apache.tomcat.jdbc.pool.DataSource;
    dataSource.setDriverClassName(driverClassName);
    dataSource.setUrl(url);
    dataSource.setUsername(username);
    dataSource.setPassword(password);
    dataSource.setTestWhileIdle(testWhileIdle);     
    dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMills);
    dataSource.setValidationQuery(validationQuery);
    return dataSource;
}

参考:Spring boot jdbc连接


2

作为另一种选择,您可以使用DriverManagerDataSource,例如:

public DataSource getDataSource(DBInfo db) {

    DriverManagerDataSource dataSource = new DriverManagerDataSource();

    dataSource.setUsername(db.getUsername());
    dataSource.setPassword(db.getPassword());
    dataSource.setUrl(db.getUrl());
    dataSource.setDriverClassName(db.getDriverClassName());

    return dataSource;
}

然而,使用它时要小心,因为:

注意:这个类不是一个真正的连接池;它实际上并不汇集连接。它只是作为完整的连接池的简单替代品,实现相同的标准接口,但在每次调用时创建新的连接。参考文献


1
NOTE: Within special class loading environments such as OSGi, this class is effectively superseded by SimpleDriverDataSource due to general class loading issues with the JDBC DriverManager that be resolved through direct Driver usage (which is exactly what SimpleDriverDataSource does). - specializt

2

对于SpringBoot 2.1.7版本,使用URL似乎无法正常工作。请改用jdbcUrl。

在属性中:

security:
      datasource:
        jdbcUrl: jdbc:mysql://ip:3306/security
        username: user
        password: pass

在Java中:

@ConfigurationProperties(prefix = "security.datasource")
@Bean("dataSource")
@Primary
public DataSource dataSource(){

    return DataSourceBuilder
            .create()
            .build();
}

1
我在 Spring-Boot 2 中定制了 Tomcat 数据源。
依赖版本:
- spring-boot: 2.1.9.RELEASE - tomcat-jdbc: 9.0.20
或许对某些人有用。

application.yml

spring:
    datasource:
        driver-class-name: org.postgresql.Driver
        type: org.apache.tomcat.jdbc.pool.DataSource
        url: jdbc:postgresql://${spring.datasource.database.host}:${spring.datasource.database.port}/${spring.datasource.database.name}
        database:
            host: localhost
            port: 5432
            name: rostelecom
        username: postgres
        password: postgres
        tomcat:
            validation-query: SELECT 1
            validation-interval: 30000           
            test-on-borrow: true
            remove-abandoned: true
            remove-abandoned-timeout: 480
            test-while-idle: true
            time-between-eviction-runs-millis: 60000
            log-validation-errors: true
            log-abandoned: true

Java

@Bean
@Primary
@ConfigurationProperties("spring.datasource.tomcat")
public PoolConfiguration postgresDataSourceProperties() {
    return new PoolProperties();
}

@Bean(name = "primaryDataSource")
@Primary
@Qualifier("primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource primaryDataSource() {
    PoolConfiguration properties = postgresDataSourceProperties();
    return new DataSource(properties);
}

主要原因是应用程序中有多个数据源,其中一个必须标记为@Primary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接