Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreIf you've used Spring Boot for a while, you're probably familiar with setting up connection details using properties. For example, you may have used spring.datasource.url
to configure a JDBC connection. In Spring Boot 3.1 this continues to work as you'd expect, but we've changed things a bit under the hood to decouple the auto-configurations from the properties.
There's now a new ConnectionDetails
abstraction.
This interface models the concept of a connection to a remote service.
If you take a look at this interface, you'll see that it's empty.
It serves as a tagging interface, and is extended by multiple other interfaces which model the connection to a concrete remote service, e.g. RedisConnectionDetails
for connections to a Redis server or JdbcConnectionDetails
for connections to a database server through JDBC.
We added the ConnectionDetails
abstraction primarily to support our brand new Docker Compose and Testcontainers features, which we will cover in depth in subsequent blog articles.
But this abstraction isn't limited to only Docker Compose or Testcontainers.
The auto-configurations in Spring Boot have been changed to use the ConnectionDetails
if they are available.
In such cases they will take even precendence over the configuration properties.
If there is no such ConnectionDetails
bean, then the properties will be used.
Let's take a look at the JdbcConnectionDetails
interface:
public interface JdbcConnectionDetails extends ConnectionDetails {
String getUsername();
String getPassword();
String getJdbcUrl();
}
This is all Spring Boot needs to know in order to connect to a JDBC database.
The URL contains which JDBC driver to use, which host to connect to, which port to use, etc.
The username and the password are needed for authentication.
This is equivalent to setting the spring.datasource.url
, spring.datasource.username
and spring.datasource.password
properties.
Note that the interface does not include methods for everything related to JDBC connections. For example, the connection pool configuration is not part of the contract. This interface only deals with the information needed to connect to a remote service, other concerns like the pool size etc. are still configured through properties.
This abstraction is useful because, sometime in the future, other interesting integrations can be built on top of it.
For example, a Spring Boot application running in VMware Tanzu cloud could discover the database which is associated to the application and automatically provide a JdbcConnectionDetails
(or R2dbcConnectionDetails
for reactive applications) bean which knows how to connect to that database.
For you as a user this means less time fiddling with Kubernetes config maps and secrets, because the application "just knows" how to connect to the database.
You'll have more time to concentrate on the important things in life like solving business problems and attending sprint meetings!
You might be wondering why a new interface is necessary when it's already possible to contribute properties for connection details.
Indeed, using connection properties outside of application.properties
is quite common.
For example, when writing integration tests with Testcontainers, the @DynamicPropertySource
feature is often used.
The problem with using properties outside of the application configuration is that they can change (and have in the past, like the spring.redis
properties did), which leads to brittle coupling.
If the property names change, the code which sets these properties still compiles, as it's all "stringly" typed.
When using ConnectionDetails
to provide the information on how to connect to a remote service, if we make backward-incompatible changes (and we won't without a good reason, we promise!), this will lead to a compile error.
This is much better than finding out about the breakage in production.
If you want to use the ConnectionsDetails
abstraction yourself, all you need to do is to define a bean with the right type, for example:
@Configuration(proxyBeanMethods = false)
class MyConnectionDetailsConfiguration {
@Bean
JdbcConnectionDetails myJdbcConnectionDetails() {
return new JdbcConnectionDetails() {
@Override
public String getUsername() {
return "myuser";
}
@Override
public String getPassword() {
return "3xtr3mly-s3cr3t";
}
@Override
public String getJdbcUrl() {
return "jdbc:postgresql://postgres-server.svc.local:5432/mydatabase?ssl=true&sslmode=required";
}
};
}
}
Now Spring Boot will automatically use these information to connect to the given PostgreSQL database.
At the time of writing, there are the following sub-interfaces:
CassandraConnectionDetails
for connections to a Cassandra serverCouchbaseConnectionDetails
for connections to a Couchbase serverElasticsearchConnectionDetails
for connections to an Elasticsearch serverJdbcConnectionDetails
for connections to a database server through JDBCKafkaConnectionDetails
for connections to a Kafka serverMongoConnectionDetails
for connections to a MongoDB serverNeo4jConnectionDetails
for connections to a Neo4J serverR2dbcConnectionDetails
for connections to a database server through R2DBCRabbitConnectionDetails
for connections to a RabbitMQ serverRedisConnectionDetails
for connections to a Redis serverZipkinConnectionDetails
for connections to a Zipkin serverWe hope you liked our little tour to the ConnectionDetails
abstraction and we're excited to see what cool things will be built on top of it!