Thursday, July 16, 2015

Spring Boot with non JDBC database url

Using Spring Boot a DataSource usually is configured using spring.datasource.* properties as shown in the following example:

spring.datasource.url=jdbc:postgresql://localhost/test
spring.datasource.username=demo
spring.datasource.password=pass
However database as a service providers (like Heroku Postgres, Compose PostgreSQL, ClearDB MySQL) provide the connection parameters in a format of
scheme://user:password@host:port/path
Would be nice to have a single URI property in Spring Boot to configure database connection properties, similar how we can configure a MongoDB connection via spring.data.mongodb.uri or a Redis connection via spring.redis.uri

Below you find how you could use a single URI property, in this case spring.datasource.uri to specify the database connection parameters to a Heroku PostgreSQL database service. The demo application is running on Heroku and using three datastore services:



The connection properties are managed on Heroku:



In the application we just reference the Heroku config variables, encapsulating them in a heroku profile.

spring.datasource.uri=${DATABASE_URL}
spring.data.mongodb.uri=${MONGOLAB_URI}
spring.redis.uri=${REDIS_URL}
Then we just need to extract the connection properties from the spring.datasource.uri and create a DataSource. In this example we use the Tomcat JDBC Connection Pool to create the DataSource instance.

public abstract class DatabaseConfig {
protected void configureDataSource(org.apache.tomcat.jdbc.pool.DataSource dataSource) {
dataSource.setMaxActive(20);
dataSource.setMaxIdle(8);
dataSource.setMinIdle(8);
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
dataSource.setValidationQuery("SELECT 1");
}
}
@Configuration
@Profile("dev")
class DevDatabaseConfig extends DatabaseConfig {
@Bean
public DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:myDB;MODE=PostgreSQL");
dataSource.setUsername("sa");
dataSource.setPassword("");
configureDataSource(dataSource);
return dataSource;
}
}
@Configuration
@Profile("heroku")
class HerokuDatabaseConfig extends DatabaseConfig {
@Value("${spring.datasource.uri}")
private String databaseUri;
@Bean
public DataSource dataSource() throws URISyntaxException {
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
URI dbUri = new URI(databaseUri);
dataSource.setUsername(dbUri.getUserInfo().split(":")[0]);
dataSource.setPassword(dbUri.getUserInfo().split(":")[1]);
dataSource.setUrl("jdbc:postgresql://" + dbUri.getHost() + ':' + dbUri.getPort() + dbUri.getPath());
configureDataSource(dataSource);
return dataSource;
}
}
The demo application is available on my github profile.