Spring Boot 3.1 的 ConnectionDetails 抽象

如果你已经使用了一段时间的Spring Boot,你可能对使用属性设置连接细节(connection details)很熟悉。例如,你可能已经使用 spring.datasource.url 来配置JDBC连接。在Spring Boot 3.1中,这仍然像你所期望的那样工作,但我们在底层做了一些改变,将自动配置与属性解耦。

现在有一个新的 ConnectionDetails 抽象。这个接口模拟了连接到远程服务的概念。如果你看一下这个接口,你会发现它是空的。它作为一个标记接口,并由其他多个接口扩展,这些接口对具体的远程服务的连接进行建模,例如,RedisConnectionDetails 用于与 Redis server 的连接,JdbcConnectionDetails 用于通过JDBC与数据库服务器的连接。

我们添加 ConnectionDetails 抽象主要是为了支持我们全新的Docker Compose和Testcontainers功能,我们将在随后的博客文章中深入介绍。但这个抽象并不只限于Docker Compose或Testcontainers。Spring Boot中的自动配置已经改为使用 ConnectionDetails,如果它们可用的话。在这种情况下,它们甚至会优先于配置属性。如果没有这样的 ConnectionDetails Bean,那么就会使用 properties 。

让我们来看看 JdbcConnectionDetails 接口:

COPYpublic interface JdbcConnectionDetails extends ConnectionDetails {

  String getUsername();

  String getPassword();

  String getJdbcUrl();

}

这是 Spring Boot 需要知道的所有信息,以便连接到JDBC数据库。URL包含要使用的JDBC驱动程序、要连接的主机、要使用的端口等。用户名和密码是认证所需的。这相当于设置 spring.datasource.urlspring.datasource.usernamespring.datasource.password 属性。

请注意,该接口并不包括与JDBC连接有关的所有方法。例如,连接池的配置不是其中的一部分。这个接口只处理连接到远程服务所需的信息,其他的关注点,如池的大小等,仍然通过 properties 来配置。

这种抽象很有用,因为在未来的某个时候,可以在它的基础上建立其他有趣的集成。例如,在 VMware Tanzu cloud 中运行的Spring Boot应用程序可以发现与该应用程序相关的数据库,并自动提供一个 JdbcConnectionDetails(或 R2dbcConnectionDetails,用于响应式应用程序)bean,该bean知道如何连接到该数据库。对于用户来说,这意味着减少了折腾 Kubernetes config maps 和 secrets 的时间,因为应用程序 “知道” 如何连接到数据库。你将有更多的时间专注于其他重要的事情,如解决业务问题。

你可能会想,既然已经可以为连接细节贡献属性了,为什么还需要一个新的接口。事实上,在 application.properties 之外使用连接属性是很常见的。例如,在用 Testcontainers 编写集成测试时,经常使用 @DynamicPropertySource 功能。

在应用程序配置之外使用属性的问题是,它们可能会发生变化(过去也曾发生过,比如 spring.redis 属性),这导致了脆性耦合。如果属性名称改变了,设置这些属性的代码仍然可以编译,因为它都是 “字符串” 类型的。当使用 ConnectionDetails 来提供如何连接到远程服务的信息时,如果我们做了向后不兼容的改变(没有一个好的理由,我们不会这么做!),这将导致一个编译错误。这比在生产中发现问题要好得多。

如果你想自己使用 ConnectionsDetails 抽象,你所需要做的就是定义一个具有正确类型的Bean,例如:

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

    };
  }

}

现在,Spring Boot 将自动使用这些信息来连接到给定的PostgreSQL数据库。

在撰写本文时,有以下子接口:

  • CassandraConnectionDetails 用于与 Cassandra server 的连接。
  • CouchbaseConnectionDetails 用于与 Couchbase server 的连接
  • ElasticsearchConnectionDetails 用于与 Elasticsearch server 的连接
  • JdbcConnectionDetails 用于通过 JDBC 与 database server 的连接。
  • KafkaConnectionDetails 用于与 Kafka server 的连接
  • MongoConnectionDetails 用于与 MongoDB server 的连接
  • Neo4jConnectionDetails 用于与 Neo4J server 的连接
  • R2dbcConnectionDetails 用于通过 R2DBC 与 database server 的连接。
  • RabbitConnectionDetails 用于与 RabbitMQ server 的连接
  • RedisConnectionDetails 用于与 Redis server 的连接
  • ZipkinConnectionDetails 用于与 Zipkin server的连接

原文: Spring Boot 3.1’s ConnectionDetails abstraction