[spring-projects/spring-boot]增强 PropertySources 以了解配置文件

2024-04-23 508 views
5

application-${profile}.propertiesBoot 加载/的功能yml非常出色,但很高兴看到它扩展到其他PropertySource功能,例如EnvironmentPostProcessoror提供的功能@PropertySource。这本质上是为向应用程序提供属性的库实现提供配置文件感知。https://github.com/Netflix/archaius/tree/2.x中提供了类似的选项,用于管理从应用程序或库加载的基于配置文件的配置。

征求意见:

1) 添加一个扩展,ResourcePropertySource可以ProfileAwareResourcePropertySource在类似的地方使用EnvironmentPostProcessor 2) 添加一个注释来@ProfileAwarePropertySource实现相同的效果。 3) 添加 aProfileAwareEnvironmentPostProcessor实质上将配置文件加载行为应用于所有现有PropertySources。

示例: @PropertySource("myprops")with profilefoo应将两个PropertySources 添加到Environment,myprops.propertiesmyprops-foo.propertiesmyprops-foo.properties应直接添加到之前,myprops.properties以便更具体的配置覆盖不太具体的配置。这应该扩展到包括多个配置文件,所应用的排序配置文件反映了它们的优先级。

这将为我们提供在每个PropertySource或全局范围内显式启用此功能的选项。有什么想法吗?

回答

6

我们不鼓励您在 Spring Boot 中使用@PropertySource,因此我个人并不热衷于该领域的任何更改。

如果我正确理解你的意思,你正在寻找一个 API,它可以完成我们为标准所做的事情,application.properties并通过某种方式在某处触发它。您能解释一下为什么目前的基础设施还不够吗?如果我没猜错的话,看来您想阅读application并且搜索位置可能有所不同mypropsmyprops我做对了吗?

1

是的,我希望能够重用我们所谓的级联属性加载(加载 application.properties、application-profile1.properties、application-profile2.properties 等)的逻辑,而不仅仅是应用程序属性。这主要用于库开发,其中库在其 jar 中包含一些属性文件。我们希望该库还能够根据当前活动的配置文件加载其属性。

举一个更具体的示例,假设您处于云/微服务安排中,您拥有一个服务 (ServiceA),并且您希望与其他服务 (ServiceB) 进行通信。另请想象,每个服务都有其部署的多个副本,用于不同级别的测试,并且每个部署都有一个配置文件。举例来说,假设这些部署各自都有给定的配置文件stagingproduction

如果我们使用 Eureka+Ribbon 之类的东西,ServiceA 需要许多配置属性来与 ServiceB 进行通信。为了减少复制/粘贴,ServiceB 可能会在客户端 jar 中发布这些配置,并使用加载这些属性的自动配置。 ServiceB 库将希望根据代码运行的环境/配置文件提供不同的属性。jar 将包含serviceb-staging.properties, 和serviceb-production.properties。该 jar 还将包含一个EnvironmentPostProcessor加载这些属性的方法,使用建议的ProfileAwareResourcePropertySource.

ServiceA 将导入此库,并且在使用staging配置文件运行时,将具有application-staging.propertiesserviceb-staging.properties。最终结果是,当 ServiceA 使用配置文件运行时,它会一致地加载在应用程序和库级别staging为配置文件指定的配置。staging

1

ServiceB 可能会在客户端 jar 中发布这些配置

库中依赖于环境的配置?我认为这是一种反模式,我觉得很奇怪。也许你应该看看 spring-cloud-config...

6

:laughing: 考虑到我们根据他们的一项服务来建模配置服务器 :wink:

6

是的,我们绝对有一个远程配置服务器,尽管我们认为使用它不仅仅是临时覆盖是一种反模式,因为将所有配置放在那里会造成中心故障点。如果您的应用程序在配置服务器不可用的情况下无法正常运行,那么当配置后端不可避免地出现故障时,这将是一个非常现实的问题。

所以我们仍然将默认配置打包在库中。我们将这些范围限制在部署考虑因素上,例如测试/生产/暂存、AWSAccount、AWS 区域等。当我们将其适应 Spring Boot 世界时,我们发现配置文件是这个概念的一个非常好的实现。但事实上,只有应用程序属性是配置文件感知的,而没有其他 PropertySource 具有相同的行为,这一事实并不完全符合我们的期望。

4

还有一些其他计划可能会提供较低级别的 API,最终可以帮助您实现此用例:#12412 可以简化 YAML 文件的加载,#3783 可以提供更丰富的 API。

3

我们也会发现这很有用。我们有一个使用 Spring Batch 的 Spring Boot 应用程序。这又使用了一些加载 Spring XML 文件的嵌套上下文。 (嵌套上下文是 Spring Batch 的一个功能,用于解决 Bean 名称冲突。)这意味着我们有一个主 Spring Boot 上下文(使用默认属性解析)以及嵌套上下文(需要依赖 @PropertySource)。

9

我认为我们现在应该关闭这个,看看新ConfigData工作的效果如何。用户现在可以轻松地进行特定于配置文件的导入,这可能不需要这样做。例如:

spring.config.import=mycustomimport:something
spring.config.activate.on-profile=production

如果上述仍然太麻烦,我们可以随时重新打开这个。

0

@l0co 被动的攻击性评论,例如“虽然 Spring 团队拒绝为其用户引入此功能,因为 Spring 团队知道最好的”,这是无益且具有破坏性的。我们可能或可能无法在任何给定时间实现某个功能的原因有很多。有时这是一件简单的事情,或者优先考虑我们认为对我们来说最重要的工作领域。

在事情变得太激烈之前,我将暂时锁定这个问题。

0

从我的角度来看,这仍然是值得考虑的有用功能。例如,我们有一些基础库堆栈,涵盖我们在项目中使用的所有技术。例如,我们有一个基于 spring data 的 mariadb 基础库。除了它提供了一些依赖项配置和管道代码以在我们项目中使用 mariadb 的所有服务中使用之外,我们还希望它提供一些基本的配置预设,然后应由所有服务使用,而不是在application.yml每个服务中重复。例如:

spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    username: ${maria.user}
    password: ${maria.pass}
    url: jdbc:mariadb://${maria.host}:${maria.port}/${maria.db}
  jpa:
    properties:
      hibernate:
        schema_update:
          unique_constraint_strategy: RECREATE_QUIETLY
        dialect: org.hibernate.dialect.MariaDB10Dialect

因此,基本上,我们不想在每个服务中重复所有这些内容,我们只希望它由库提供,并且服务配置仅限于此:

maria:
  user: ...
  pass: ...
  db: ...

这可以使用@PropertySources自定义 bean 来完成,但不幸的是它既不支持开箱即用的 yaml,也不支持自定义配置文件。出于多种原因,我们需要自定义配置文件配置。例如,我们可能希望有一些配置文件可以启用详细的 SQL 日志,或者我们可能希望能够使用某些配置文件打开或关闭二级缓存。目前我们无法做到这一点,因为@PropertySources非常有限。

在我看来,spring.config.import这不是一个正确的解决方案,因为我们至少必须在使用我们的库的所有服务中重复此导入行,对于我们想要支持的每个配置文件也是如此,考虑到我们有大约 15 个这样的库,这将产生很大的影响复制并粘贴要包含在每个服务中的代码application.yml

Spring 中有一个可以正常工作的代码,支持 yaml、配置文件、新配置文件处理等。为什么不在实现中使用相同的代码@PropertySource并删除当前的自定义实现呢?

顺便说一句,是我在当前 spring 实现中实现相同结果的工作解决方法。

3

不幸的是,默认情况下很难更改@PropertySource为这样的工作方式,因为它是 Spring 框架的一部分,并且实际上不应该了解 Spring Boot 问题。我认为我们能做的最好的事情就是在 Spring Boot 中提供一个PropertySourceFactory实现,它将提供一种加载文件的固定方式。

即使如此,它也会有点棘手,因为(正如您所发现的)很难将环境放入加载器中。我们也许能够对框架进行更改,以便PropertySourceFactory实现也可以EnvironmentAware。我们需要以某种方式共享的代码来自StandardConfigDataLocationResolver.

标记为团队讨论,看看是否有任何其他想法可以帮助我们扩展@PropertySource

0

@l0co 您可能可以使用的另一种抽象是EnvironmentPostProcessor。如果您在此之后订购ConfigDataEnvironmentPostProcessor,它应该会为您提供Environment应用了配置文件的信息。您可以PropertySources根据需要添加额外的内容。

4

我可以理解,这个功能是框架的一部分,不可能只在 Spring Boot 中引入。

在这种情况下,我看不出可以对这个主题做更多的事情。也许只是一些如何实现它的明确示例,也许作为提到的 stackoverflow 线程的答案,人们首先被引导,在谷歌中寻找这个问题的解决方案。它可以是我的方式,使用EnvironmentAwareEnvironmentPostProcessor。无论可行,最简单的方法可能就是最好的方法。

也许,在我的解决方案中寻找示例,如果MyPropertySourceFactory我在那里提出的这种解决方案成为 Spring Boot 的一部分,并在文档中提供清晰的用例描述,那么用户可能会更容易使用它。