在 Cloud Foundry 中使用 Spring Boot 绑定到数据服务

工程 | Dave Syer | 2015年4月27日 | ...

本文探讨了如何将Spring Boot应用程序绑定到数据服务(JDBC、NoSQL、消息传递等),以及Cloud Foundry中默认和自动行为的各种来源,并提供了一些关于使用哪些以及在什么条件下哪些将处于活动状态的指导。Spring Boot 提供了许多自动配置和外部绑定功能,其中一些与 Cloud Foundry 相关,而许多则无关。Spring Cloud Connectors是一个可在应用程序中使用的库,如果要以编程方式创建自己的组件,可以使用它,但它本身不会做任何“神奇”的事情。最后是 Cloud Foundry 的java buildpack,它具有“自动重新配置”功能,试图减轻将简单应用程序迁移到云端的负担。正确配置中间件服务(如 JDBC 或 AMQP 或 Mongo)的关键在于了解每个工具提供的功能、它们在运行时如何相互影响,以及如何打开和关闭它们的部分功能。目标应该是应用程序在开发人员桌面上本地执行到 Cloud Foundry 中的测试环境,最终到 Cloud Foundry(或其他)中的生产环境的平滑过渡,而无需更改源代码或打包,符合十二要素应用程序指南。

本文附带一些简单的源代码。要使用它,您可以克隆存储库并将其导入您喜欢的 IDE。您需要从完整项目中删除两个依赖项才能到达我们开始讨论具体代码示例的相同点,即spring-boot-starter-cloud-connectorsauto-reconfiguration

注意:本文讨论的所有库的当前坐标为org.springframework.boot:spring-boot-*:2.2.5.RELEASEorg.springframework.cloud:spring-cloud-*-connector:1.0.8.RELEASEorg.cloudfoundry:auto-reconfiguration:2.11.0.RELEASE

提示:github 中的源代码包含一个docker-compose.yml文件。如果您没有运行的 MySQL 数据库,可以使用它来创建本地 MySQL 数据库。您实际上不需要它来运行下面的大部分代码,但它可能有助于验证它是否真的有效。

急于求成者的结论

如果您想跳过细节,而您只需要一个使用 H2 在本地运行和使用 MySQL 在云中运行的方案,那么从这里开始,以后当您想更深入地了解时再阅读其余部分。(对于其他数据服务,如 RabbitMQ、Redis、Mongo 等,也存在类似的选项。)

您的第一个也是最简单的选择是根本什么都不做:根本不定义DataSource,而是将 H2 放入类路径中。当您在本地运行时,Spring Boot 将为您创建一个嵌入式 H2 DataSource。Cloud Foundry buildpack 将检测数据库服务绑定并在您在云中运行时为您创建一个DataSource。如果您也添加 Spring Cloud Connectors,那么只要您包含一个连接器,您的应用程序也可以在其他云平台上运行。如果您只想让某些东西工作,这可能就足够了。

如果您想在生产环境中运行一个严肃的应用程序,您可能需要调整一些连接池设置(例如池的大小、各种超时、重要的测试借用标志)。在这种情况下,buildpack 自动重新配置的DataSource将无法满足您的要求,您需要选择一个替代方案,并且有许多或多或少明智的选择。

最简单的选择是设置一个环境变量JBP_CONFIG_SPRING_AUTO_RECONFIGURATION='{ enabled: false }',并使用spring.datasource.*属性(例如在application.properties或该属性的特定于配置文件的版本中)在运行时设置其他属性。“cloud”配置文件由 buildpack 自动为您激活。例如:

spring.datasource.url: ${vcap.services.mysql.credentials.jdbcUrl:jdbc:h2:mem:testdb}
spring.datasource.username: ${vcap.services.mysql.credentials.username:sa}
spring.datasource.password: ${vcap.services.mysql.credentials.password:}
spring.datasource.testOnBorrow: true

以及您需要的任何其他spring.datasource.*属性。

另一个选择是使用Spring Cloud Connectors显式创建DataSource,但受“cloud”配置文件保护

@Configuration
@Profile("cloud")
public class DataSourceConfiguration {

  @Bean
  public Cloud cloud() {
    return new CloudFactory().getCloud();
  }

  @Bean
  @ConfigurationProperties(DataSourceProperties.PREFIX)
  public DataSource dataSource() {
    return cloud().getSingletonServiceConnector(DataSource.class, null);
  }

}

现在来看细节。我们需要构建应用程序在运行时发生情况的图像,以便从中学习如何为配置数据服务做出明智的选择。

自动配置层

让我们来看一个带有DataSource的简单应用程序(类似的考虑也适用于 RabbitMQ、Mongo、Redis)

@SpringBootApplication
public class CloudApplication {
	
	@Autowired
	private DataSource dataSource;
	
	public static void main(String[] args) {
		SpringApplication.run(CloudApplication.class, args);
	}

}

这是一个完整的应用程序:DataSource 可以是@Autowired,因为它是由 Spring Boot 为我们创建的。DataSource 的细节(具体类、JDBC 驱动程序、连接 URL 等)取决于类路径上的内容。让我们假设应用程序通过spring-boot-starter-jdbc(或spring-boot-starter-data-jpa)使用 Spring JDBC,因此它有一个来自 Tomcat 的DataSource实现(即使它不是 Web 应用程序),这就是 Spring Boot 使用的。

考虑一下发生的情况

  • 类路径除了启动器之外还包含 H2(仅):DataSource是来自DataSourceAutoConfiguration的 Tomcat 高性能池,它连接到内存数据库“testdb”。

  • 类路径包含 H2 和 MySQL:DataSource仍然是 H2(与之前相同),因为我们没有为 MySQL 提供任何额外的配置,并且 Spring Boot 无法猜测连接的凭据。

  • spring-boot-starter-cloud-connectors添加到类路径:DataSource没有变化,因为 Spring Cloud Connectors 没有检测到它们正在云平台上运行。启动器附带的提供程序都查找特定的环境变量,除非您设置它们或在 Cloud Foundry、Heroku 等中运行应用程序,否则它们将找不到这些变量。

  • 使用spring.profiles.active=cloud在“cloud”配置文件中运行应用程序:DataSource还没有变化,但这是Java buildpack在您的应用程序在 Cloud Foundry 中运行时所做的工作之一。

  • 在“cloud”配置文件中运行并提供一些环境变量来模拟在 Cloud Foundry 中运行并绑定到 MySQL 服务

VCAP_APPLICATION={"name":"application","instance_id":"FOO"}
VCAP_SERVICES={"mysql":[{"name":"mysql","tags":["mysql"],"credentials":{"uri":"mysql://root:root@localhost/test"}}]}

(“tags”提供了一个提示,说明我们想要创建一个 MySQL DataSource,“uri”提供了位置,“name”成为 bean ID)。DataSource现在使用通过VCAP_*环境变量提供的凭据使用 MySQL。Spring Boot 对 Connectors 有一些自动配置,因此如果您查看应用程序中的 bean,您将看到一个CloudFactory bean,以及DataSource bean(ID 为“mysql”)。自动配置相当于向您的应用程序配置中添加@ServiceScan。只有当您的应用程序在“cloud”配置文件中运行,并且只有当没有现有类型的@BeanCloud,并且配置标志spring.cloud.enabled不是“false”时,它才处于活动状态。

  • 添加来自 Java buildpack 的“auto-reconfiguration”JAR(Maven 坐标org.cloudfoundry:auto-reconfiguration:2.11.0.RELEASE)。您可以将其添加为本地依赖项以模拟在 Cloud Foundry 中运行应用程序,但这对于真实的应用程序来说并不正常(这只用于试验自动配置)。“auto-reconfiguration”JAR 现在拥有创建DataSource所需的一切,但它(尚未)这样做,因为它检测到您已经有一个类型为CloudFactory的 bean,一个由 Spring Boot 添加的 bean。

  • 删除显式的“cloud”配置文件。当您的应用程序启动时,配置文件仍然处于活动状态,因为“auto-reconfiguration”JAR 会再次添加它。DataSource仍然没有变化,因为 Spring Boot 通过@ServiceScan为您创建了它。

  • 删除spring-boot-starter-cloud-connectors依赖项,以便 Spring Boot 停止创建CloudFactory。“auto-reconfiguration”JAR 实际上拥有它自己的 Spring Cloud Connectors 副本(所有具有不同包名称的类),并且它现在使用它们来创建DataSource(在BeanFactoryPostProcessor中)。Spring Boot 自动配置的DataSource被一个通过VCAP_SERVICES绑定到 MySQL 的替换了。无法控制池属性,但如果可用,它仍然使用 Tomcat 池(不支持 Hikari 或 DBCP2)。

  • 删除“auto-reconfiguration”JAR,DataSource将恢复为 H2。

提示:将 web 和 actuator 启动器与endpoints.health.sensitive=false一起使用,以便通过“/health”快速检查DataSource。您还可以使用“/beans”、“/env”和“/autoconfig”端点来查看自动配置中发生了什么以及原因。

注意:在 Cloud Foundry 中运行或在本地类路径中包含“auto-reconfiguration”JAR 都将激活“cloud”配置文件(原因相同)。VCAP_*环境变量是使 Spring Cloud 和/或“auto-reconfiguration”JAR 创建 bean 的因素。

注意:VCAP_SERVICES 中的 URL 实际上并非“jdbc”模式,而这对于 JDBC 连接来说是必需的。然而,这是 Cloud Foundry 通常呈现它的格式,因为它适用于除 Java 之外的几乎所有语言。Spring Cloud Connectors 或构建包自动重新配置(如果它们正在创建 DataSource)会将其为您转换为 jdbc:* URL。

注意:MySQL URL 还包含用户名和密码以及数据库名称,这些对于示例源代码中 docker-compose.yml 创建的 Docker 容器是有效的。如果您有使用不同凭据的本地 MySQL 服务器,您可以替换它们。

提示:如果您使用本地 MySQL 服务器并想验证它是否已连接,您可以使用 Spring Boot Actuator 中的“/health”端点(示例代码中已包含)。或者您可以在类路径的根目录中创建一个 schema-mysql.sql 文件,并在其中放入一个简单的保持活动查询(例如 SELECT 1)。Spring Boot 将在启动时运行它,因此如果应用程序成功启动,则表示您已正确配置数据库。

自动重新配置 JAR 始终位于 Cloud Foundry(默认情况下)的类路径中,但如果它找到 org.springframework.cloud.CloudFactory bean(如果 CloudAutoConfiguration 处于活动状态,则由 Spring Boot 提供),则会避免创建任何 DataSource。因此,如果连接器也存在于 Spring Boot 应用程序中,则将其添加到类路径的最终效果只是启用“cloud”配置文件。您可以在应用程序启动时的日志中看到它做出跳过自动重新配置的决定。

015-04-14 15:11:11.765  INFO 12727 --- [           main] urceCloudServiceBeanFactoryPostProcessor : Skipping auto-reconfiguring beans of type javax.sql.DataSource
2015-04-14 15:11:57.650  INFO 12727 --- [           main] ongoCloudServiceBeanFactoryPostProcessor : Skipping auto-reconfiguring beans of type org.springframework.data.mongodb.MongoDbFactory
2015-04-14 15:11:57.650  INFO 12727 --- [           main] bbitCloudServiceBeanFactoryPostProcessor : Skipping auto-reconfiguring beans of type org.springframework.amqp.rabbit.connection.ConnectionFactory
2015-04-14 15:11:57.651  INFO 12727 --- [           main] edisCloudServiceBeanFactoryPostProcessor : Skipping auto-reconfiguring beans of type org.springframework.data.redis.connection.RedisConnectionFactory
...
etc.

创建您自己的 DataSource

上一节介绍了各种库中最重要的自动配置功能。如果您想自己掌控,您可以从创建自己的 DataSource 实例开始。例如,您可以使用 DataSourceBuilder,这是一个便捷类,它是 Spring Boot 的一部分(它根据类路径选择实现)。

@SpringBootApplication
public class CloudApplication {
	
	@Bean
	public DataSource dataSource() {
		return DataSourceBuilder.create().build();
	}
	
	...

}

我们定义的 DataSource 是无用的,因为它没有连接 URL 或任何凭据,但这很容易解决。让我们运行这个应用程序,就像它在 Cloud Foundry 中一样:使用 VCAP_* 环境变量和自动重新配置 JAR,但在类路径中不使用 Spring Cloud Connectors,也不使用显式的“cloud”配置文件。构建包会激活“cloud”配置文件,创建一个 DataSource 并将其绑定到 VCAP_SERVICES。正如前面简要描述的那样,它会完全移除您的 DataSource 并将其替换为手动注册的单例(这不会显示在 Spring Boot 中的“/beans”端点中)。

现在将 Spring Cloud Connectors 添加回类路径,看看再次运行它时会发生什么。它实际上在启动时失败了!发生了什么?@ServiceScan(来自 Connectors)会查找绑定的服务,并为它们创建 bean 定义。这有点像构建包,但不同之处在于它不会尝试替换任何相同类型的现有 bean 定义。因此,您会收到一个自动连接错误,因为有两个 DataSource,并且无法选择一个注入到应用程序中各种需要它的地方。

为了解决这个问题,我们将不得不控制 Cloud Connectors(或者干脆不使用它们)。

使用 CloudFactory 创建 DataSource

您可以通过创建一个 Cloud 实例作为 @Bean 来禁用 Spring Boot 自动配置和 Java 构建包自动重新配置。

@Bean
public Cloud cloud() {
  return new CloudFactory().getCloud();
}

@Bean
@ConfigurationProperties(DataSourceProperties.PREFIX)
public DataSource dataSource() {
  return cloud().getSingletonServiceConnector(DataSource.class, null);
}

优点:Spring Boot 中的 Connectors 自动配置已回退,因此只有一个 DataSource。可以根据 Spring Boot 用户指南,通过 spring.datasource.* 属性使用 application.properties 进行调整。

缺点:它不适用于 VCAP_* 环境变量(或其他一些云平台)。它还依赖于用户记住创建 Cloud 作为 @Bean 以禁用自动配置。

总结:我们仍然没有处于舒适的位置(一个没有一些复杂的运行环境变量操作就无法运行的应用程序在实践中并没有多大用处)。

双运行:本地使用 H2,云端使用 MySQL

Spring Cloud Connectors 中有一个本地配置文件选项,因此您不必在真正的云平台中才能使用它们,但尽管是样板代码,但设置起来很麻烦,而且当您真正的云平台中时,您还必须以某种方式将其关闭。最后一点非常重要,因为您最终需要一个本地文件来在本地运行,但只能在本地运行,它不能与应用程序代码的其余部分一起打包(例如,违反了十二要素原则)。

因此,为了继续使用我们显式的 @Bean 定义,最好坚持使用主流的 Spring 和 Spring Boot 功能,例如使用“cloud”配置文件来保护 DataSource 的显式创建。

@Configuration
@Profile("cloud")
public class DataSourceConfiguration {

  @Bean
  public Cloud cloud() {
    return new CloudFactory().getCloud();
  }

  @Bean
  @ConfigurationProperties(DataSourceProperties.PREFIX)
  public DataSource dataSource() {
    return cloud().getSingletonServiceConnector(DataSource.class, null);
  }

}

有了这个,我们就有了一个在本地和 Cloud Foundry 中都能顺利工作的解决方案。在本地,Spring Boot 将创建一个使用 H2 内嵌数据库的 DataSource。在 Cloud Foundry 中,它将绑定到类型为 DataSource 的单例服务,并关闭 Spring Boot 中自动配置的 DataSource。它还有一个好处,就是可以与 Spring Cloud Connectors 支持的任何平台一起工作,例如,相同的代码可以在 Heroku 和 Cloud Foundry 上运行。由于 @ConfigurationProperties,您可以将额外的配置绑定到 DataSource,以便在生产环境中需要时调整连接池属性等。

注意:我们一直在使用 MySQL 作为示例数据库服务器,但实际上 PostgreSQL 至少是一个同样引人注目的选择,甚至更多。例如,当与本地的 H2 配合使用时,您可以将 H2 设置为“Postgres 兼容”模式,并在两种环境中使用相同的 SQL。

手动创建本地和云端 DataSource

如果您喜欢创建 DataSource bean,并且想要在本地和云端都这样做,您可以使用 2 个配置文件(例如“cloud”和“local”)。但是,然后您必须找到一种方法在不在云端时默认激活“local”配置文件。Spring 中已经内置了一种方法可以做到这一点,因为始终存在一个名为“default”(默认情况下)的默认配置文件。所以这应该可以工作。

@Configuration
@Profile("default") // or "!cloud"
public class LocalDataSourceConfiguration {
	
	@Bean
    @ConfigurationProperties(DataSourceProperties.PREFIX)
	public DataSource dataSource() {
		return DataSourceBuilder.create().build();
	}

}

@Configuration
@Profile("cloud")
public class CloudDataSourceConfiguration {

  @Bean
  public Cloud cloud() {
    return new CloudFactory().getCloud();
  }

  @Bean
  @ConfigurationProperties(DataSourceProperties.PREFIX)
  public DataSource dataSource() {
    return cloud().getSingletonServiceConnector(DataSource.class, null);
  }

}

在这个简单的示例中,“default” DataSource 实际上与自动配置的 DataSource 相同,因此除非您需要这样做,例如创建 Spring Boot 不支持的类型的自定义具体 DataSource,否则您不会这样做。您可能会认为这一切都变得有点复杂,但实际上 Spring Boot 并没有让它变得更难,我们只是在处理需要控制两种环境中 DataSource 构造的后果。

在本地使用非嵌入式数据库

如果您不想在本地使用 H2 或任何内存数据库,那么您实际上无法避免必须配置它(Spring Boot 可以从 URL 中猜测很多内容,但至少需要它)。因此,您至少需要设置一些 spring.datasource.* 属性(例如 URL)。这并不难做到,您可以使用其他配置文件轻松地在不同环境中设置不同的值,但是一旦您这样做,当您进入云端时,您就需要关闭默认值。为此,您可以为“default”配置文件(例如 application-default.properties)在特定于配置文件的文件(或 YAML 文档)中定义 spring.datasource.* 属性,而这些属性不会在“cloud”配置文件中使用。

纯声明式方法

如果您不想编写Java代码,或者不想使用Spring Cloud Connectors,您可能想要尝试使用Spring Boot自动配置和外部属性(或YAML)文件来完成所有操作。例如,如果Spring Boot在类路径中找到合适的配置,它会为您创建一个DataSource,并且可以通过application.properties完全控制它,包括您在生产环境中需要的DataSource的所有细粒度功能(例如池大小和验证查询)。因此,您只需要一种方法来从环境中发现服务的地址和凭据。构建包将Cloud Foundry VCAP_*环境变量转换为Spring Environment中可用的属性源。因此,例如,DataSource配置可能如下所示

spring.datasource.url: ${cloud.services.mysql.connection.jdbcurl:jdbc:h2:mem:testdb}
spring.datasource.username: ${cloud.services.mysql.connection.username:sa}
spring.datasource.password: ${cloud.services.mysql.connection.password:}
spring.datasource.testOnBorrow: true

属性名称中的“mysql”部分是Cloud Foundry中的服务名称(因此由用户设置)。当然,相同的模式也适用于各种服务,而不仅仅是JDBC DataSource。一般来说,使用外部配置,特别是@ConfigurationProperties是一个好习惯,因为它们允许最大的灵活性,例如在运行时使用系统属性或环境变量进行覆盖。

注意:Spring Boot提供了类似的功能,它提供vcap.services.*而不是cloud.services.*,因此您实际上有多种方法可以做到这一点。但是,JDBC url的名称略有不同,所以要注意“jdbcurl”和“jdbcUrl”的区别。示例

spring.datasource.url: ${vcap.services.mysql.credentials.jdbcUrl:jdbc:h2:mem:testdb}
spring.datasource.username: ${vcap.services.mysql.credentials.username:sa}
spring.datasource.password: ${vcap.services.mysql.credentials.password:}
spring.datasource.testOnBorrow: true

通常,非JDBC服务可以使用相应的vcap.services.*credentials.url正常工作。

这种方法的一个限制是,如果应用程序需要配置Spring Boot本身不提供的bean(例如,如果需要2个DataSource),则该方法不适用,在这种情况下,无论如何您都必须编写Java代码,并且可以选择使用属性文件对其进行参数化。

但是,在您自己尝试之前,请注意,除非您还禁用了构建包自动重新配置(以及类路径上的Spring Cloud Connectors),否则它实际上不起作用。如果不这样做,它们会为您创建一个新的DataSource,而Spring Boot无法将其绑定到您的属性文件。因此,即使对于这种声明式方法,您也需要一个环境变量JBP_CONFIG_SPRING_AUTO_RECONFIGURATION='{ enabled: false }'或一个Cloud bean的显式@Bean定义

@Configuration
@Profile("cloud")
public class CloudDataSourceConfiguration {

  @Bean
  public Cloud cloud() {
    return new CloudFactory().getCloud();
  }

}

这纯粹是为了关闭构建包自动重新配置(以及Spring Boot自动配置,但这可以通过属性文件条目禁用)。

注意:如果您使用JBP_CONFIG_SPRING_AUTO_RECONFIGURATION关闭构建包自动重新配置,您也会关闭“cloud”配置文件。当然,很容易将其添加回来。

混合声明式和显式Bean定义

您也可以混合这两种方法:声明单个@Bean定义,以便您可以控制对象的构造,但使用@ConfigurationProperties将附加配置绑定到它(并在本地和Cloud Foundry中执行相同的操作)。示例

@Configuration
public class LocalDataSourceConfiguration {
	
	@Bean
    @ConfigurationProperties(DataSourceProperties.PREFIX)
	public DataSource dataSource() {
		return DataSourceBuilder.create().build();
	}

}

(其中DataSourceBuilder将被替换为您用例所需的任何花哨的逻辑)。application.properties将与上面相同,包含您生产设置所需的任何其他属性。

第三种方法:发现凭据并手动绑定

另一种适用于平台和环境独立性的方法是为Spring Boot用于绑定其自动配置连接器的@ConfigurationProperties bean声明显式bean定义。例如,要设置DataSource的默认值,您可以声明类型为DataSourceProperties@Bean

@Bean
@Primary
public DataSourceProperties dataSourceProperties() {
    DataSourceProperties properties = new DataSourceProperties();
    properties.setInitialize(false);
    return properties;
}

这将为“initialize”标志设置默认值,并允许从application.properties(或其他外部属性)绑定其他属性。将其与Spring Cloud Connectors结合使用,您可以在检测到云服务时控制凭据的绑定


@Autowired(required="false")
Cloud cloud;

@Bean
@Primary
public DataSourceProperties dataSourceProperties() {
    DataSourceProperties properties = new DataSourceProperties();
    properties.setInitialize(false);
    if (cloud != null) {
      List<ServiceInfo> infos = cloud.getServiceInfos(RelationalServiceInfo.class);
      if (infos.size()==1) {
        RelationalServiceInfo info = (RelationalServiceInfo) infos.get(0);
        properties.setUrl(info.getJdbcUrl());
        properties.setUsername(info.getUserName());
        properties.setPassword(info.getPassword());
      }
    }
    return properties;
}

并且您仍然需要在“cloud”配置文件中定义Cloud bean。最终会产生相当多的代码,在这个简单的用例中是相当不必要的,但是如果您有更复杂的绑定,或者需要实现一些逻辑来在运行时选择DataSource,则可能会有用。

Spring Boot为您可能常用的其他中间件提供了类似的*Properties bean(例如RabbitPropertiesRedisPropertiesMongoProperties)。一个标记为@Primary的此类bean实例足以重置自动配置连接器的默认值。

部署到多个云平台

到目前为止,我们只关注Cloud Foundry作为部署应用程序的唯一云平台。Spring Cloud Connectors的一个不错的功能是它支持其他平台,无论是开箱即用还是作为扩展点。spring-boot-starter-cloud-connectors甚至包括Heroku支持。如果您什么都不做,并且依赖于自动配置(懒惰程序员的方法),那么您的应用程序将可以部署在您在类路径上拥有连接器的所有云中(如果您使用启动器,则为Cloud Foundry和Heroku)。如果您采用显式@Bean方法,则需要确保在非Cloud Foundry平台上激活“cloud”配置文件,例如通过环境变量。如果您使用纯声明式方法(或任何涉及属性文件的组合),则需要激活“cloud”配置文件,并且可能还需要激活特定于您平台的另一个配置文件,以便正确的属性文件最终在运行时进入Environment

自动配置和提供行为总结

  • 如果Spring Boot在类路径上找到所有合适的配置,它会提供DataSource(还有RabbitMQ或Redis ConnectionFactory、Mongo等)。使用“spring-boot-starter-*”依赖项足以激活此行为。

  • 如果Spring Boot在类路径上找到Spring Cloud Connectors,它还会提供一个可自动装配的CloudFactory(但只有在找到类型为Cloud@Bean时才会关闭)。

  • Spring Boot中的CloudAutoConfiguration还会有效地向您的应用程序添加一个@CloudScan,如果您需要创建自己的DataSource(或类似的),则需要将其关闭。

  • Cloud Foundry Java构建包会检测Spring Boot应用程序并激活“cloud”配置文件,除非它已经处于活动状态。如果您想在本地尝试,添加构建包自动重新配置JAR也会执行相同的操作。您可以使用JBP_CONFIG_SPRING_AUTO_RECONFIGURATION='{ enabled: false }'禁用它。

  • 通过自动重新配置JAR,如果构建包没有找到CloudFactory bean或Cloud bean(以及其他一些bean),构建包也会启动并创建DataSource(RabbitMQ、Redis、Mongo等也是如此)。因此,在Spring Boot应用程序中包含Spring Cloud Connectors会关闭“自动重新配置”行为的这一部分(bean创建)。

  • 关闭Spring Boot CloudAutoConfiguration很容易,但是如果您这样做,如果您不想要构建包自动重新配置,则必须记住也要将其关闭。有两种方法可以做到这一点。一种是环境变量:JBP_CONFIG_SPRING_AUTO_RECONFIGURATION='{ enabled: false }'。另一种是定义一个bean定义(例如,可以是CloudCloudFactory类型)。

  • Spring Boot 将application.properties(以及其他外部属性来源)绑定到@ConfigurationProperties bean,包括但不限于其自动配置的那些 bean。您可以使用此功能来调整池属性和其他需要在生产环境中不同的设置。

一般建议和结论

在这篇简短的文章中,我们已经看到了相当多的选项和自动配置,并且我们实际上只使用了三个库(Spring Boot、Spring Cloud Connectors 和 Cloud Foundry buildpack 自动重新配置 JAR)和一个平台(Cloud Foundry),不包括本地部署。buildpack 功能实际上只对非常简单的应用程序有用,因为没有灵活性来调整生产环境中的连接。也就是说,在原型设计时,这是一个不错的方法。如果您想实现本地和云端部署相同代码的目标,同时仍然能够在生产环境中进行必要的调整,则只有三种主要方法:

  1. 使用 Spring Cloud Connectors 显式创建DataSource和其他中间件连接,并使用@Profile("cloud")保护这些@Beans。这种方法始终有效,但会导致比许多应用程序所需的代码更多。

  2. 使用 Spring Boot 默认自动配置并使用application.properties(或 YAML)声明云绑定。为了充分利用它,您还必须显式关闭 buildpack 自动重新配置。

  3. 使用 Spring Cloud Connectors 发现凭据,如果存在,则将其绑定到 Spring Boot @ConfigurationProperties 作为默认值。

这三种方法实际上并不冲突,可以使用@ConfigurationProperties混合使用,以提供特定于配置文件的默认配置覆盖(例如,以不同的方式在生产环境中设置连接池)。如果您有一个相对简单的 Spring Boot 应用程序,那么选择这些方法之间的方法可能仅仅是个人喜好。如果您有一个非 Spring Boot 应用程序,那么显式@Bean方法将胜出,如果您计划在多个云平台(例如 Heroku 和 Cloud Foundry)中部署您的应用程序,它也可能胜出。

注意:这篇博客是一次发现之旅(谁知道有这么多东西要学习?)。感谢所有帮助审阅和评论的人,特别是Scott Frederick,他发现了草稿中的大多数错误,并且总是有时间查看新的修订版本。

获取 Spring 时事通讯

通过 Spring 时事通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获得支持

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

了解更多

即将举行的活动

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

查看全部