覆盖 Spring Cloud Config 中的远程属性值

1、概览

Spring Cloud Config 是 Spring Cloud 全家桶的一个子项目。它通过集中式独立的服务来管理各个服务的配置。Spring Cloud Config 拥有自己的属性管理库,但也可以集成 Git、Consul 和 Eureka 等开源项目。

在本文中,我们将了解在 Spring Cloud Config 中覆盖远程属性值的不同方法,以及 Spring 从 2.4 版本开始强制实施的限制,以及 3.0 版本中的变化。在本教程中,我们使用 Spring Boot 2.7.2。

2、创建 Spring Config Server

使用 Spring Cloud Config 创建外部化的配置服务器。

2.1、创建配置文件

application.properties 文件中定义的配置与所有客户端应用共享。也可以为指定应用或指定 Profile 定义特定配置。

首先,创建一个配置文件,其中包含为客户端应用提供的属性。

客户端应用命名为 baeldung,在 /resources/config 文件夹中创建 baeldung.properties 文件。

2.2、添加属性

baeldung.properties 文件中添加一些属性,然后在客户端应用中使用这些属性:

hello=Hello Jane Doe!
welcome=Welcome Jane Doe!

还要在 resources/config/application.properties 文件中添加一个共享属性,Spring 将在所有客户端中共享该属性:

shared-property=This property is shared accross all client applications

2.3、Spring Boot Config Server

现在,创建 Spring Boot 应用以提供配置服务。需要添加 Spring-cloud-config-server 依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

创建应用并启用配置服务器:

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServer.class, args);
    }
}

在应用的 application.properties 文件中添加以下属性,告诉它从 8081 端口启动,并加载先前定义的配置:

server.port=8081
spring.cloud.config.server.native.searchLocations=classpath:/config

现在,启动服务器,激活 native Profile,使用文件系统作为配置存储库:

mvn spring-boot:run -Drun.profiles=native

服务启动成功,且正常提供配置服务。验证共享属性是否可访问:

$ curl localhost:8081/unknownclient/default
{
  "name": "unknownclient",
  "profiles": [
    "default"
  ],
  "label": null,
  "version": null,
  "state": null,
  "propertySources": [
    {
      "name": "classpath:/config/application.properties",
      "source": {
        "shared-property": "This property is shared accross all client applications"
      }
    }
  ]
}

以及应用(baeldung)所特有的属性:

$ curl localhost:8081/baeldung/default
{
  "name": "baeldung",
  "profiles": [
    "default"
  ],
  "label": null,
  "version": null,
  "state": null,
  "propertySources": [
    {
      "name": "classpath:/config/baeldung.properties",
      "source": {
        "hello": "Hello Jane Doe!",
        "welcome": "Welcome Jane Doe!"
      }
    },
    {
      "name": "classpath:/config/application.properties",
      "source": {
        "shared-property": "This property is shared accross all client applications"
      }
    }
  ]
}

通过路径参数向服务器指定了应用的名称和使用的 Profile(default)。

配置服务器没有禁用 spring.cloud.config.server.accept-empty 属性(默认为 true ),所以应用名称可以是未知的(unknownclient)。

3、客户端

创建一个客户端程序,在启动时加载服务器提供的配置。

3.1、项目设置 & 依赖

pom.xml 中添加 spring-cloud-starter-configspring-boot-starter-web

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.2、创建客户端应用

接下来,创建客户端程序,从 spring-cloud-config 服务器读取配置:

@SpringBootApplication
public class Client {
    public static void main(String[] args) {
        SpringApplication.run(Client.class, args);
    }
}

3.3、获取配置

修改 application.properties 文件,以从配置服务器获取配置:

spring.cloud.config.name=baeldung
spring.config.import=optional:configserver:http://localhost:8081

还指定了应用的名称为 baeldung,用于从配置服务器加载特定的属性。

3.4、添加示例 Controller

现在,创建一个 Controller,负责显示配置的特定属性以及共享属性:

@RestController
public class HelloController {

    @Value("${hello}")
    private String hello;

    @Value("${welcome}")
    private String welcome;

    @Value("${shared-property}")
    private String shared;

    @GetMapping("hello")
    public String hello() {
        return this.hello;
    }

    @GetMapping("welcome")
    public String welcome() {
        return this.welcome;
    }

    @GetMapping("shared")
    public String shared() {
        return this.shared;
    }
}

现在,我们可以请求如下三个 URL,以验证配置是否已被成功读取、加载:

$ curl http://localhost:8080/hello
Hello Jane Doe!
$ curl http://localhost:8080/welcome
Welcome Jane Doe!
$ curl http://localhost:8080/shared
This property is shared accross all client applications

4、在服务端重写属性

通过修改服务器配置,可以覆盖为特定应用定义的属性。

编辑服务器的 resources/application.properties 文件,覆盖 hello 属性:

spring.cloud.config.server.overrides.hello=Hello Jane Doe – application.properties!

再次测试对 /hello Controller 的调用,以验证修改是否生效:

$ curl http://localhost:8080/hello
Hello Jane Doe - application.properties!

可以在 resources/config/application.properties 文件添加此属性。在这种情况下,它将覆盖上面定义的属性。

5、在客户端重写属性

自 Spring Boot 2.4 版起,已无法通过客户端应用的 application.properties 文件覆盖属性。

5.1、使用 Spring Profile

不过,我们可以使用 Spring Profile。在本地 Profile 中定义的属性比在服务器级别为应用定义的优先级更高。

在客户端应用中添加一个配置文件 application-development.properties,覆盖 hello 属性:

hello=Hello local property!

现在,激活 development Profile,启动客户端:

mvn spring-boot:run -Drun.profiles=development

再次测试 /hello Controller,以验证是否覆盖:

$ curl http://localhost:8080/hello
Hello local property!

5.2、使用占位符

我们可以使用占位符为属性赋值。这样,服务器可以提供一个默认值,该值可被客户端定义的属性覆盖。

从服务器的 resources/application.properties 文件中移除 hello 属性,并修改 config/baeldung.properties 中的属性,使用占位符:

hello=${app.hello:Hello Jane Doe!}

这里指定了一个默认值,如果客户端声明了名为 app.hello 的属性,就会覆盖该值。

编辑客户端的 resources/application.properties 文件,添加该属性:

app.hello=Hello, overriden local property!

再次测试 hello Controller,以验证是否成功覆盖了默认值:

$ curl http://localhost:8080/hello
Hello, overriden local property!

注意,如果在 Profile 配置中也定义了 hello 属性,则后者优先。

6、传统配置

自 Spring Boot 2.4 起,我们可以通过启用 “传统配置” 的方式,来使用 Spring Boot 2.4 版改动之前的旧属性管理系统。

6.1、加载外部配置

在 2.4 版之前,外部配置由 Bootstrap 管理,这需要 spring-cloud-starter-bootstrap 依赖。

将其添加到 pom.xml 中:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

接下来,在 resources 文件夹中创建 bootstrap.properties 文件,并配置服务器的访问 URL:

spring.cloud.config.name=baeldung
spring.cloud.config.uri=http://localhost:8081

application.properties 中启用 “传统配置”:

spring.config.use-legacy-processing=true

6.2、启用重写功能

在服务器端,需要通过配置以启动属性覆盖功能。修改 baeldung.properties

spring.cloud.config.overrideNone=true

此时,外部属性的优先级不会高于应用 JAR 中定义的属性。

6.3、覆盖服务器属性

现在,我们可以通过 application.properties 文件在客户端应用中覆盖 hello 属性:

hello=localproperty

调用 Controller,测试属性是否被覆盖:

$ curl http://localhost:8080/hello
localproperty

6.4、“传统配置” 已过时

自 Spring Boot 3.0 版起,“启用传统配置” 不再可行。在这种情况下,应该使用上文提出的其他方法。

7、总结

在本文中,我们学习了在 Spring Cloud Config 中覆盖远程属性值的多种方法。


参考:https://www.baeldung.com/spring-cloud-config-remote-properties-override