Configure DataSource programmatically in Spring Boot

JavaSpringDatasourceSpring BootCredential Providers

Java Problem Overview


With Spring Boot I can instantiate a JdbcTemplate with the following:

Code:

@Autowired
private JdbcTemplate jdbcTemplate;

Properties:

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

This create a DataSource of class: org.apache.tomcat.jdbc.pool.DataSource

How do I set the DataSource username/password programmatically?

We have a policy not to store credentials in plain text and I have to use a specific credential provider where I work.

Java Solutions


Solution 1 - Java

You can use DataSourceBuilder if you are using jdbc starter. Also, in order to override the default autoconfiguration bean you need to mark your bean as a @Primary

In my case I have properties starting with datasource.postgres prefix.

E.g

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

If it is not feasible for you, then you can use

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

Solution 2 - Java

My project of spring-boot has run normally according to your assistance. The yaml datasource configuration is:

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

Custom DataSource

@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();
    }
}

Solution 3 - Java

All you need to do is annotate a method that returns a DataSource with @Bean. A complete working example follows.

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

Solution 4 - Java

If you're using latest spring boot (with jdbc starter and Hikari) you'll run into: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName. To solve this:

  1. In your application.properties:

datasource.oracle.url=youroracleurl

  1. In your application define as bean (@Primary is mandatory!):
@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();
}

Solution 5 - Java

If you want more datesource configs e.g.

spring.datasource.test-while-idle=true 
spring.datasource.time-between-eviction-runs-millis=30000
spring.datasource.validation-query=select 1

you could use below code

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

refer: https://stackoverflow.com/questions/29729909/spring-boot-jdbc-connection

Solution 6 - Java

As an alternative way you can use DriverManagerDataSource such as:

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

However be careful about using it, because:

> NOTE: This class is not an actual connection pool; it does not > actually pool Connections. It just serves as simple replacement for a > full-blown connection pool, implementing the same standard interface, > but creating new Connections on every call. reference

Solution 7 - Java

for springboot 2.1.7 working with url seems not to work. change with jdbcUrl instead.

In properties:

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

In java:

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

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

Solution 8 - Java

I customized Tomcat DataSource in Spring-Boot 2.

Dependency versions:

  • spring-boot: 2.1.9.RELEASE
  • tomcat-jdbc: 9.0.20

May be it will be useful for somebody.

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

The main reason why it had been done is several DataSources in application and one of them it is necessary to mark as a @Primary.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarsellus WallaceView Question on Stackoverflow
Solution 1 - JavaEddú MeléndezView Answer on Stackoverflow
Solution 2 - JavaAlfer WeiView Answer on Stackoverflow
Solution 3 - JavaRodrigo Villalba ZayasView Answer on Stackoverflow
Solution 4 - JavaACVView Answer on Stackoverflow
Solution 5 - JavazhuguoweiView Answer on Stackoverflow
Solution 6 - JavaMMKaramiView Answer on Stackoverflow
Solution 7 - JavaChristian Altamirano AyalaView Answer on Stackoverflow
Solution 8 - JavaVladimirView Answer on Stackoverflow