引入 java-cfenv:一个用于访问 Cloud Foundry 服务的新库

发布 | Mark Pollack | 2019 年 2 月 15 日 | ...

引言

Spring Cloud Connectors 库自 2011 年 Cloud Foundry 发布以来就一直伴随我们。连接器库和 Cloud Foundry 的 Java buildpack 的主要目标之一是“当你想要开始使用 Cloud Foundry 时,减少初始投入”。连接器库使用 VCAP_SERVICES 环境变量中包含的信息,创建连接到数据库等支持服务所需的 Spring bean 定义。然后,buildpack 通过一项称为“自动重新配置”(auto-reconfiguration)的功能,用连接器库创建的 bean 定义替换应用程序中原有的 bean 定义。当你将应用程序推送到 Cloud Foundry 时,可能已经在日志中看到过相关的提及……

-----> Downloading Spring Auto Reconfiguration 2.5.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-2.5.0_RELEASE.jar

自动重新配置对于入门来说非常方便。然而,当你需要更多控制时,例如改变与 DataSource 相关的连接池大小,它就没那么方便了。这需要编写连接器特定的代码,并且它不像 Spring Boot 那样提供许多连接池选项。同样的限制也适用于其他支持服务。

这就引出了一个问题:为什么我们有两个相互竞争的机制来创建服务基础设施 bean?我们不能让 Spring Boot 为我们处理所有这些事情吗?这就是创建我们新的 java-cfenv 库的动机。

引入 java-cfenv

java-cfenv 库的灵感来源于 Cloud Foundry 生态系统中其他地方使用的 node-cfenvpy-cfenv 库。这些库提供了一个简单的 API,用于从 VCAP_SERVICES 环境变量中包含的 JSON 字符串中检索凭据。我们将首先介绍 Java API(我们预计它不会经常被使用),然后展示它如何与 Spring 和 Spring Boot 的自动配置功能集成。

核心 API 包含五个类

  • CfEnv,负责解析 VCAP_SERVICESVCAP_APPLICATION 环境变量的内容。
  • CfApplication,提供用于访问 VCAP_APPLICATION 环境变量内容的访问器。
  • CfEnv 上的查找方法返回 CfService 类的实例。
  • CfService 提供用于获取服务的名称、标签、tabs 和计划的访问器,以及一个 CfCredentials 对象。
  • CfCredentials 提供用于获取用户名、密码、主机、端口和 URI 的访问器。URI 使用 UriInfo 类表示。

例如,如果您在 Cloud Foundry 中将 MySql 服务绑定到您的应用程序,VCAP_SERVICES 环境变量将包含如下条目

{
 "p-mysql": [
    {
      "credentials": {
        "hostname": "10.0.4.35",
        "port": 3306,
        "name": "cf_2e23d10a_8738_8c3c_66cf_13e44422698c",
        "username": "8McHri7aKbuTEGCR",
        "password": "J2BNJYkeXAH9idkG",
        "uri": "mysql://8McHri7aKbuTEGCR:[email protected]:3306/cf_2e23d10a_8738_8c3c_66cf_13e44422698c?reconnect=true",
        "jdbcUrl": "jdbc:mysql://10.0.4.35:3306/cf_2e23d10a_8738_8c3c_66cf_13e44422698c?user=8McHri7aKbuTEGCR&password=J2BNJYkeXAH9idkG"
      },
      "syslog_drain_url": null,
      "volume_mounts": [],
      "label": "p-mysql",
      "provider": null,
      "plan": "100mb",
      "name": "mysql",
      "tags": [
        "mysql",
        "relational"
      ]
    }
  ]
}

当使用 java-cfenv API 时,我们可以通过几个简单的方法调用获取凭据信息,然后以编程方式创建到数据库的连接。

CfEnv cfEnv = new CfEnv();
CfService cfService = cfEnv.findServiceByName(“mysql”);
String plan = cfService.getPlan(); // 100mb
CfCredentials cfCredentials = cfService.getCredentials();
String password = cfCredentials.getPassword(); // J2BNJYkeXAH9idkG
UriInfo uriInfo = cfCredentials.getUriInfo();
String username = uriInfo.getUsername(); // 8McHri7aKbuTEGCR

findServiceByName 方法接受一个正则表达式,以帮助在可能对服务命名略有不同的不同 Cloud Foundry 环境中提供一些可移植性。还有其他查找方法,帮助您从标签(tag)和标签(label)等中进行选择。

数据库支持

在前面的例子中,您可能只想获取 JSON 字段 jdbcUrl,以便将其传递给 DataSource。您可以使用 API 来完成此操作

String jdbcUrl = cfCredentials.getString(“jdbcUrl”);

然而,Cloud Foundry 上的并非所有数据库服务都提供了这个方便的字段。实际上,Cloud Foundry 上各种数据库服务提供的字段可能相当随意。现有的连接器库已经开发了启发式算法来处理这种差异,并且此功能已被移植到新的 java-cfenv 库中。它在 CfEnvJdbc 类中可用

CfEnvJdbc cfEnvJdbc = new CfEnvJdbc();
CfJdbcService cfJdbcService = cfEnvJdbc.findJdbcService();
String jdbcUrl = cfJdbcService.getUrl();

如果应用程序绑定了多个数据库服务,方法 findJdbcService 将抛出异常。在这种情况下,您可以使用方法 findJdbcServiceByName 从多个数据库服务中进行选择。

String jdbcUrl1 = cfEnvJdbc.findJdbcServiceByName('mysqlA').getUrl();
String jdbcUrl2 = cfEnvJdbc.findJdbcServiceByName('mysqlB').getUrl();

与 Spring 一起使用

如果您使用的是 Spring 而不是 Spring Boot,您可以将 CfJdbcEnv 实例注册为一个 bean,然后使用 Spring Expression Language 调用其方法来设置应用程序属性。

@Bean
public CfJdbcEnv cfJdbcEnv() {
  return new CfJdbcEnv();
}

然后在属性文件中,访问 CfJdbcEnv 实例

myDatasourceUrl=#{ cfJdbcEnv.findJdbcService().getUrl() }

与 Spring Boot 一起使用

大多数 Spring Boot 用户无需直接使用 java-cfenv API。java-cfenv 库包含 Spring Boot 的 EnvironmentPostProcessor 实现,可以自动设置已知的 Spring Boot 属性。这使得 Spring Boot 的自动配置能够生效,同时仍然可以通过环境变量或其他更高优先级的环境属性源覆盖值。

start.spring.io 生成项目后,您需要做的就是手动将 java-cfenv-boot 依赖项添加到您的项目中,并在将应用程序推送到 Cloud Foundry 时禁用自动重新配置。对于 maven,依赖项是

<dependency>
  <groupId>io.pivotal.cfenv</groupId>
  <artifactId>java-cfenv-boot</artifactId>
  <version>1.0.0.M1</version>
</dependency>

由于这目前是一个里程碑构建(milestone build),您需要添加一个里程碑 <repository> 配置,例如

<repository>
   <id>spring-milestones</id>
   <name>Spring Milestones</name>
   <url>http://repo.spring.io/libs-milestone-local</url>
</repository>

要禁用自动重新配置,请使用以下命令或在 manifest 文件中使用其等效配置。

cf set-env <APP> JBP_CONFIG_SPRING_AUTO_RECONFIGURATION '{enabled: false}'

由于自动重新配置还会设置 cloud profile,许多应用程序都依赖于此 profile,您可能还需要显式地设置此 profile。

cf set-env <APP> SPRING_PROFILES_ACTIVE cloud

如果您使用 manifest 文件,条目将是

env:
 SPRING_PROFILES_ACTIVE: cloud
 JBP_CONFIG_SPRING_AUTO_RECONFIGURATION: '{enabled: false}'

值得注意的是,在生产环境中,您无论如何都应该这样做。

要设置连接池属性,您现在只需使用标准的 Spring Boot 属性,例如 spring.datasource.maxActive=10 以及其他更具体的连接池属性。

下一步是什么?

有关如何使用 java-cfenv 库的更多信息可在 GitHub 上获取。当前版本是 1.0.0.M1,由于它将在本月晚些时候被纳入 Data Flow 2.0 GA 版本,因此很快就会发布 GA 版本。一如既往,我们欢迎您的反馈和贡献,即使这些反馈和贡献导致需要破坏性 API 更改,并在 1.0 版本发布后不久合并到 java-cfenv 2.0 版本中。

java-cfenv 的 1.0 GA 版本将支持 Spring Cloud Connectors 项目中的所有服务,因为它们受到 Spring Boot 自动配置的良好支持。届时,现有的 Connectors 库将进入维护模式。当然会解决关键的 bug 和安全问题,但不会添加新功能。在 java-cfenv 的 1.0 GA 版本发布时,将提供一份将应用程序从 Spring Cloud Connectors 迁移到 java-cfenv 的指南。

在项目页面上列出了基于核心 Connectors 项目构建的其他库。这些扩展项目可以继续使用 Connectors,但鼓励维护者迁移到以 Boot 为中心的方法。

订阅 Spring 电子报

通过 Spring 电子报保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速前进。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看全部