简体   繁体   中英

Spring Boot externalised configuration for DataSource not working

I have an application - using Spring 4.3.6 and Spring Boot 1.4.4 - which will be exported as a JAR. I want to connect to a remote Oracle database but I am having trouble externalising the configuration without breaking the application.

This is my current workaround:

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;
}

With the above, my application is able to connect to the database and execute queries successfully. However, when I try to externalise the configuration as follows:

@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

I will get the following error when trying to execute jdbcTemplate.update(query) in my Spring Boot Controller (note that without externalising the above works):

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

I have tried to remove @ConfigurationProperties and change app.datasource to spring.datasource . I have also tried to use DataSourceBuilder.create().build() which returns javax.sql.DataSource but the same error is thrown in both cases.

I'm doing something wrong. What's the correct way to successfully externalise the configuration?

Suppose you have two datasources for two different Oracle databases. Then you have the following properties file:

/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

Then in a configuration file:

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;
  }
}

If you want to specify the external location of your application.properties file when running the jar, then set the spring.config.location as a system property, you can try:

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

Make sure the application.properties file is excluded when building the jar

There should be no need to create the DataSource yourself.

Make sure you have the

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

Dependecy in your classpath and the oracle driver and put following properties in your application.properties file:

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

After that you should be able to @Autowired your DataSource

For more information have a look at: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database

You cannot override the predefined properties provided by spring boot.

Just use the following properties in application.properties file.

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

See Also : https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Apart from above, to clarify @ConfigurationProperties is used at class level and the prefix "app" not "app.datasource"

@ConfigurationProperties(prefix = "app")

Now you have a class named DbProperties and the properties of the class is same as the last part of the key in application.properties

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

Now the actual config/component class should look like following.

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

    public DBProperties getDatasource() {
        return datasource;
    }

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

Please note

  1. The instance variable name is datasource which is same as the second part of the key
  2. datasource is a class level instance

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM