Spring Cloud Consul 动态配置

Spring Cloud Consul 动态配置

简介

如同 Nacos 一样 Consul 也支持配置存储,并且也提供了配置自动更新的机制。

项目搭建

创建 Spring Cloud 项目,然后按照如下配置引入依赖包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ext {
set('springCloudVersion', "2022.0.0-M5")
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-config'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
implementation('org.springframework.cloud:spring-cloud-starter-bootstrap')
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}

编辑 Spring 配置文件 application.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spring:
application:
name: <name>
cloud:
consul:
host: ${CONSUL_HOST:localhost}
port: ${CONSUL_PORT:8500}
discovery:
prefer-ip-address: true
tags: version=1.0
instance-id: ${spring.application.name}:${spring.cloud.client.hostname}:${spring.cloud.client.ip-address}:${server.port}
healthCheckInterval: 15s

server:
port: 8080
error:
include-message: always
include-exception: true
servlet:
encoding:
charset: UTF-8

编辑引入配置文件 bootstrap.yaml

1
2
3
4
5
6
7
8
9
10
11
spring:
cloud:
consul:
config:
enabled: true
defaultContext: <name>
profileSeparator: '-'
prefixes: config
format: properties
watch:
enabled: true

注:此处支持的 format 有 yaml, properties, key_value, files 可以根据实际情况进行选用。

编辑 Spring 主类并添加如下注解:

1
2
3
4
5
6
7
8
9
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableDiscoveryClient
@EnableScheduling
@SpringBootApplication
public class DynApplication {
}

编辑 Spring 配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Getter
@Setter
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "my")
public class MyProperties {

private String prop;

}

编辑调试接口类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import com.example.dyn.conf.MyProperties;
import jakarta.annotation.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/demo")
public class DemoController {

@Value("http://${spring.cloud.consul.host}:${spring.cloud.consul.port}/v1/kv/${spring.cloud.consul.config.prefixes}/${spring.cloud.consul.config.defaultContext}-${spring.profiles.active}/data")
String consulUrl;

@Resource
MyProperties myProperties;

@GetMapping
public HttpEntity<String> get() {
return new HttpEntity<>(myProperties.getProp());
}

@PutMapping
public HttpEntity<String> put(@RequestParam String prop) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> content = new LinkedMultiValueMap<>();
content.put("my.prop", Collections.singletonList(prop));
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(content, headers);
ResponseEntity<Object> response = restTemplate.exchange(consulUrl, HttpMethod.PUT, entity, Object.class);
if (response.getStatusCode().is2xxSuccessful()) {
return new HttpEntity<>(prop);
} else {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "consul set error");
}
}

}

启动程序即可

流程测试

如需手动编辑可以访问 consul webUI 的 Key/Value 选项中编辑配置向相关配置:

配置目录如下:

1
config/<name>/data

配置内容如下:

1
my.prop=demo-1

也可以通过 REST API 进行编辑,请求样例如下:

request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
### 写入配置项
PUT http://localhost:8080/demo?prop=edit

### 获取配置项
GET http://localhost:8080/demo

### 使用 Consul HTTP 接口读取配置项
GET http://localhost:8500/v1/kv/config/dyn-default/data

### 使用 Consul HTTP 接口编辑配置项
PUT http://localhost:8500/v1/kv/config/dyn-default/data
Content-Type: application/x-www-form-urlencoded

my.prop=idea-http

注:配置项的空间上限是 512 kb。

配置变更监听

在配置变更的时候可以采用如下的监听器,针对变更的配置完成业务逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.endpoint.event.RefreshEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class CustomRefreshEventListener implements ApplicationListener<RefreshEvent> {

@Override
public void onApplicationEvent(RefreshEvent event) {
log.error("checked");
}

}

参考资料

Spring Cloud Consul 官方文档

Consul KV store HTTP 接口手册


Spring Cloud Consul 动态配置
https://wangqian0306.github.io/2022/consul-config/
作者
WangQian
发布于
2022年11月4日
许可协议