数据源的 Spring Boot 外部化配置不起作用

Posted

技术标签:

【中文标题】数据源的 Spring Boot 外部化配置不起作用【英文标题】:Spring Boot externalised configuration for DataSource not working 【发布时间】:2017-02-10 09:11:22 【问题描述】:

我有一个应用程序 - 使用 Spring 4.3.6 和 Spring Boot 1.4.4 - 将作为 JAR 导出。我想连接到远程 Oracle 数据库,但在不破坏应用程序的情况下将配置外部化时遇到了问题。

这是我目前的解决方法:

import org.apache.tomcat.jdbc.pool.DataSource;

@Bean
public DataSource dataSource() 
  DataSource dataSource = new DataSource();

  dataSource.setUrl("jdbc:oracle:thin:@ip-address:port:orcl");
  dataSource.setUsername("user");
  dataSource.setPassword("password");
  dataSource.setDriverClassName("oracle.jdbc.OracleDriver");

  return dataSource;

通过以上操作,我的应用程序能够连接到数据库并成功执行查询。但是,当我尝试将配置外部化如下:

@Bean
@ConfigurationProperties(prefix="app.datasource")
public DataSource dataSource() 
  return new DataSource();


// application.properties
app.datasource.url=jdbc:oracle:thin:@ip-address:port:orcl
app.datasource.username=user
app.datasource.password=password
app.datasource.driver-class-name=oracle.jdbc.OracleDriver

尝试在我的 Spring Boot Controller 中执行 jdbcTemplate.update(query) 时会出现以下错误(请注意,没有外部化上述工作):

org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: The url cannot be null

我已尝试删除 @ConfigurationProperties 并将 app.datasource 更改为 spring.datasource。我也尝试使用返回javax.sql.DataSourceDataSourceBuilder.create().build(),但在两种情况下都会引发相同的错误。

我做错了什么。成功将配置外部化的正确方法是什么?

【问题讨论】:

为什么还要创建自己的DataSource... 一开始我并没有创建自己的。我使用的是 hsqldb,但它没有访问 Oracle 数据库的权限。我问了一个问题,答案是改成ojdbc,所以我就这么做了。现在它找不到自动装配到 jdbctemplate 的 bean,所以我去阅读了 spring 参考(自从我开始研究这个以来第 n 次),我认为问题是 DataSource 不知何故不存在,所以我猜我在做什么可能算作一个自定义数据源,因此我为什么要创建一个。现在它不会使用 application.properties 设置自动配置自己... hsqldb 不是甲骨文...所以显然这永远行不通。您需要正确的驱动程序,而这些都不需要手动配置。此外,异常状态(清楚地)表明数据源存在但无法建立连接,因此(可能)您的用户名/密码组合有问题。基本上你只需要删除你的配置,在你的application.properties重启中用spring.替换app.并检查你的异常。 【参考方案1】:

假设您有两个数据源用于两个不同的 Oracle 数据库。然后你有以下属性文件:

/path/to/config/application.properties

oracle1.username=YourUser1
oracle1.password=YourPassword1
oracle1.url=jdbc:oracle:thin:@localhost:1521:XE

oracle2.username=YourUser2
oracle2.password=YourPassword2
oracle2.url=jdbc:oracle:thin:@192.168.0.3:1521:XE

然后在一个配置文件中:

import oracle.jdbc.pool.OracleDataSource;

@Configuration
public class DatasourcesConfig 

@Autowired
private Environment env;

@Primary
@Bean(name = "dataSource1")
DataSource oracle1DataSource() throws SQLException 

    OracleDataSource dataSource = new OracleDataSource();
    dataSource.setUser(env.getProperty("oracle1.username"));
    dataSource.setPassword(env.getProperty("oracle1.password"));
    dataSource.setURL(env.getProperty("oracle1.url"));
    return dataSource;


@Bean(name = "dataSource2")
DataSource oracle2DataSource() throws SQLException 

    OracleDataSource dataSource = new OracleDataSource();
    dataSource.setUser(env.getProperty("oracle2.username"));
    dataSource.setPassword(env.getProperty("oracle2.password"));
    dataSource.setURL(env.getProperty("oracle2.url"));
    return dataSource;
  

如果你想在运行jar时指定你的application.properties文件的外部位置,那么将spring.config.location设置为系统属性,你可以试试:

java -jar target/your-application-0.0.1.jar -Dspring.config.location=/path/to/config/

确保在构建 jar 时排除 application.properties 文件

【讨论】:

【参考方案2】:

应该不需要创建DataSourceyourself。

确保你有

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

依赖于您的类路径和 oracle 驱动程序,并将以下属性放入您的 application.properties 文件中:

spring.datasource.url=jdbc:oracle:thin:@ip-address:port:orcl
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

之后你应该可以@Autowired你的DataSource

有关更多信息,请查看: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database

【讨论】:

【参考方案3】:

您不能覆盖 spring boot 提供的预定义属性。

只需在application.properties 文件中使用以下属性即可。

spring.datasource.url=jdbc:oracle:thin:@ip-address:port:orcl
spring.datasource.data-username=user
spring.datasource.data-password=password
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

另见:https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

除此之外,澄清@ConfigurationProperties用于类级别,前缀"app"不是"app.datasource"

@ConfigurationProperties(prefix = "app")

现在你有一个名为DbProperties的类,该类的属性与application.properties中键的最后一部分相同

public class DBProperties 
    private String url;
    private String username;
    private String password;
    // setters and getters

现在实际的配置/组件类应该如下所示。

@Component
@ConfigurationProperties(prefix = "app")
public class MyComponent 
    DBProperties datasource = new DBProperties();

    public DBProperties getDatasource() 
        return datasource;
    

    public void setDatasource(DBProperties datasource) 
        this.datasource = datasource;
        

请注意

    实例变量名称为datasource,与key的第二部分相同 datasource 是一个类级别的实例

【讨论】:

以上是关于数据源的 Spring Boot 外部化配置不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何理解 Spring Boot 应用程序已准备好工作?

Spring Boot 外部化属性不起作用

使用 EhCache 进行 Spring Boot 缓存不起作用

Spring/Spring Boot的外部化配置

Spring Boot:如何外部化 JDBC 数据源配置?

具有多个数据源和外部配置的 Spring Boot,Spring JPA