Files
odboy 182765e4a0 feat: 新增 Spring Boot 3 客户端 SDK 及 demo
- 新增 kenaito-conf-springboot3-client,支持配置拉取、增量同步、@Value/@ConfigurationProperties 动态刷新和本地缓存

- 新增 kenaito-conf-springboot3-client-demo(端口 8084)及 Dockerfile.springboot3

- 完善中英文 README、Docker 部署文档,修正 Spring Boot 2 客户端配置键名与 demo 端口说明

- 修复增量同步将服务端 code=0 成功响应误判为错误的问题
2026-08-22 21:02:15 +08:00

266 lines
9.2 KiB
Markdown

# Kenaito Config Center Spring Boot 3 Client
English | [中文](README.md)
A config center client for Spring Boot 3.x / JDK 17+ applications. It fetches remote configuration at startup, polls for incremental changes, refreshes `@Value` and `@ConfigurationProperties` fields at runtime, and falls back to a local cache when the config center is unavailable.
## Features
- Fetches all configs before the Spring context starts and injects them into the `Environment`
- Polls for incremental changes (add, update, delete) without restarting the application
- Refreshes `@Value` fields and `@ConfigurationProperties` beans automatically
- Notifies `ConfigChangeHanlder` beans on every change
- Local file cache (`config-cache.log`) used as a fallback when the config center is down
- Sensitive values masked in logs
- Multiple config center addresses (`base-url` separated by `,` or `;`) with automatic failover
- Spring Boot 3 auto-configuration (`AutoConfiguration.imports`)
## Requirements
| Item | Version |
|------|---------|
| JDK | 17+ |
| Spring Boot | 3.x |
| Maven | 3.6+ |
> For Spring Boot 2.x / JDK 8 applications use [`kenaito-conf-springboot2-client`](../kenaito-conf-springboot2-client/README_EN.md).
## Installation
### Maven
```xml
<dependency>
<groupId>cn.odboy</groupId>
<artifactId>kenaito-conf-springboot3-client</artifactId>
<version>1.0.0</version>
</dependency>
```
### Local install (for development)
```bash
cd kenaito-conf-springboot3-client
mvn clean install
```
## Quick Start
### 1. Add configuration
Add the config center settings to `application.properties`:
```properties
# Config center address (multiple addresses can be separated by commas)
kenaito.config.base-url=http://localhost:8080
# Application name (required)
kenaito.config.app-name=my-app
# Environment (dev/daily/prod)
kenaito.config.profile=daily
# Config version (default: latest)
kenaito.config.version=latest
# Auth token (required when the application enables token validation)
kenaito.config.token=your-token
# Enable remote config (default: true)
kenaito.config.enabled=true
# Sync interval in seconds (default: 60)
kenaito.config.sync-interval-seconds=10
# Keys masked in logs (comma separated)
kenaito.config.sensitive-keys=password,secret,key,token
```
YAML is supported as well:
```yaml
kenaito:
config:
base-url: http://localhost:8080
app-name: my-app
profile: daily
version: latest
sync-interval-seconds: 10
```
### 2. Inject configs with @Value
```java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigController {
@Value("${database.host:localhost}")
private String databaseHost;
@Value("${database.port:3306}")
private Integer databasePort;
@Value("${feature.enabled:false}")
private Boolean featureEnabled;
@GetMapping("/config")
public String config() {
return databaseHost + ":" + databasePort + ", feature=" + featureEnabled;
}
}
```
Values from the config center override local properties with the same key.
### 3. Use @ConfigurationProperties
```java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "database")
public class DatabaseProperties {
private String host;
private Integer port;
private String username;
private String password;
// getters and setters
}
```
### 4. Listen for changes
Implement `ConfigChangeHanlder` and register it as a Spring bean:
```java
import cn.odboy.confcenter.ConfigChangeHanlder;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class MyConfigChangeListener implements ConfigChangeHanlder {
@Override
public void onConfigChanged(Map<String, Object> changedConfigs) {
changedConfigs.forEach((key, value) ->
System.out.printf("config changed: %s = %s%n", key, value));
}
}
```
### 5. Automatic refresh
When configuration changes in the config center, the client will, within the next sync interval:
1. Update the values in `ConfigcenterContext`;
2. Update the `kenaitoConfigPropertySource` in the Spring `Environment`;
3. Invoke every `ConfigChangeHanlder` bean;
4. Refresh the affected `@Value` fields and `@ConfigurationProperties` fields.
Example refresh log:
```
[RefreshScope] refreshed @Value field: cn.odboy.demo.ConfigController.host | old='10.0.0.1' | new='10.0.0.2'
[RefreshScope] refreshed @ConfigurationProperties field: cn.odboy.demo.DatabaseProperties.port = '13306'
```
> Unlike Spring Cloud's `@RefreshScope`, this client refreshes fields directly via reflection and does not require `spring-cloud-context`.
## Configuration Reference
| Property | Description | Default | Required |
|----------|-------------|---------|----------|
| `kenaito.config.base-url` | Config center address, multiple addresses separated by `,` or `;` | - | Yes |
| `kenaito.config.app-name` | Application name (application code in the config center) | `spring.application.name` | Yes |
| `kenaito.config.profile` | Environment identifier | `dev` | No |
| `kenaito.config.version` | Config version | `latest` | No |
| `kenaito.config.token` | Auth token | empty | No |
| `kenaito.config.enabled` | Enable remote config | `true` | No |
| `kenaito.config.sync-interval-seconds` | Incremental sync interval (seconds) | `60` | No |
| `kenaito.config.global-ignore` | Ignore business group global configs | `false` | No |
| `kenaito.config.sensitive-keys` | Keys masked in logs (comma separated) | `password,passwd,key,secret,token,credentials` | No |
| `kenaito.config.local-storage-dir` | Local cache directory | Application working directory | No |
> Camel case variants (`baseUrl`, `appName`) and the legacy `kenaito.configcenter.*` prefix are also accepted. The kebab-case keys above are recommended.
## Auto-configuration
The client relies on Spring Boot 3 auto-configuration. No manual bean registration is needed:
- `KenaitoEnvironmentInitializer`
An `EnvironmentPostProcessor` registered via `META-INF/spring.factories`. It fetches remote configs before the Spring context starts and adds them as the highest-priority property source.
- `KenaitoRefreshAutoConfiguration`
Auto-configuration registered via `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`. It:
- gives the `ApplicationContext` to the client;
- registers `RefreshScopeRegistry` (`BeanPostProcessor`) to collect `@Value` fields and `@ConfigurationProperties` beans;
- refreshes affected fields when configs change.
### Differences from the Spring Boot 2 client
| Item | Spring Boot 2 client | Spring Boot 3 client |
|------|----------------------|----------------------|
| JDK | 8+ | 17+ |
| Spring Boot | 2.x | 3.x |
| Auto-configuration registration | `META-INF/spring.factories` | `META-INF/spring/...AutoConfiguration.imports` |
| Public API | `ConfigChangeHanlder`, etc. | Same |
## Demo
Demo project: [`kenaito-conf-springboot3-client-demo`](../kenaito-conf-springboot3-client-demo/)
```bash
# Install the client into the local repository first
cd kenaito-conf-springboot3-client
mvn clean install
# Start the demo
cd ../kenaito-conf-springboot3-client-demo
mvn spring-boot:run
```
Demo defaults:
- Port: `8084`
- Application name: `kenaito-springboot-demo` (override with `KENAITO_APP_NAME`)
- Environment: `daily` (override with `KENAITO_ENV`)
- Config center: `http://localhost:8080` (override with `KENAITO_BASE_URL`)
Endpoints:
| Endpoint | Description |
|----------|-------------|
| `GET /` | Application info and some configs |
| `GET /config` | Configs injected via `@Value` |
| `GET /configprops` | Configs bound via `@ConfigurationProperties` |
| `GET /changes` | The 20 most recent config changes |
| `GET /health` | Health check |
## Local Cache and Disaster Recovery
After a successful fetch, the client writes the remote configs to `config-cache.log` (in the application working directory by default, configurable via `kenaito.config.local-storage-dir`).
If the config center is unavailable and a cache exists, the client loads configs from the cache so the application can still start. Polling keeps retrying and resumes syncing once the config center is back.
## Notes
1. **Refresh type limits**: `@Value` refresh supports `String`, `int/Integer`, `long/Long`, `boolean/Boolean`, `double/Double`, `float/Float`, `short/Short`, `byte/Byte` and `char/Character`. Other types are assigned as strings.
2. **Priority**: remote configs override local properties with the same key; config center connection settings (`kenaito.config.*`) come from local configuration.
3. **Startup**: the application fails to start when `base-url` or `app-name` is missing. A temporarily unavailable config center does not block startup (without a cache only local configs are used).
4. **Masking**: values whose keys contain a sensitive word are logged as the first half of the value followed by `****`.
5. **Multiple instances**: every instance polls independently; change detection is based on the `lastTime` timestamp.
## Changelog
- **1.0.0** - Initial release for Spring Boot 3 / JDK 17