【问题标题】:Configure DataSource programmatically in Spring Boot在 Spring Boot 中以编程方式配置 DataSource
【发布时间】:2015-05-03 11:56:05
【问题描述】:

使用 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

这会创建一个 DataSource 类:org.apache.tomcat.jdbc.pool.DataSource

如何以编程方式设置 DataSource 用户名/密码?

我们的政策是不以纯文本形式存储凭据,我必须在我工作的地方使用特定的凭据提供程序。

【问题讨论】:

    标签: java spring datasource spring-boot credential-providers


    【解决方案1】:

    如果您使用的是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();
    }
    

    【讨论】:

    • @Primary 不是必需的,因为 AutoConfiguration 仅在未定义其他 bean 时创建一个 DataSource bean。
    • create() 应该是第一个
    • 主要不需要。 @Bean 使 Spring boot 能够注册配置。驱动类名、url、用户、密码需要
    • 根据 JavaDoc @Primary “表明当多个候选者有资格自动装配单值依赖项时,应优先考虑 bean。” docs.spring.io/spring/docs/current/javadoc-api/org/…
    • 但是设置spring.datasource.validation-queryspring.datasource.test-while-idlespring.datasource.time-between-eviction-runs-millis怎么样
    【解决方案2】:

    在您的帮助下,我的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();
        }
    }
    

    【讨论】:

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

    您需要做的就是用@Bean 注释一个返回DataSource 的方法。 下面是一个完整的工作示例。

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

    【讨论】:

      【解决方案4】:

      如果您使用的是最新的 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。
      • 有一种更简单的方法:在应用程序属性(即 applicaiotion.yml)中将:spring.datasource.url 重命名为 spring.datasource.jdbc-url。这应该可以解决问题! (在我的情况下是这样 - SpringBoot v2.3.2)
      【解决方案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 Connection

      【讨论】:

        【解决方案6】:

        作为替代方法,您可以使用 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;
        }
        

        但是要小心使用它,因为:

        注意:这个类不是一个实际的连接池;它不是 实际上池连接。它只是作为一个简单的替代品 成熟的连接池,实现相同的标准接口, 但在每次通话时创建新的连接。 reference

        【讨论】:

        • 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).
        【解决方案7】:

        对于使用 url 的 springboot 2.1.7 似乎不起作用。改为使用 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();
        }
        

        【讨论】:

          【解决方案8】:

          我在 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);
          }
          

          这样做的主要原因是应用程序中有几个DataSources,其中一个需要标记为@Primary

          【讨论】:

            猜你喜欢
            • 2015-09-24
            • 2017-02-24
            • 1970-01-01
            • 2020-03-09
            • 2021-02-16
            • 1970-01-01
            • 2018-03-13
            • 2016-05-03
            • 2015-02-04
            相关资源
            最近更新 更多