1. Why not use nacos
The previous project used nacos as the configuration center. During the use, there were still many problems:
- The choice of nacos is to use the service registration and discovery of nacos at the same time, but in the production environment, many projects have suffered from split-brain failures, including the service discovery capability of
nacos that was abandoned after versions 1.x and 2.x, and only configuration center capability - nacos has its own management background, which needs to maintain the account password separately, which is not convenient for management.
Note: It seems that LDAP is also supported, so I didn’t research - It can only be edited based on the rich text box of the browser, and the editing operation is inconvenient
Note: Copy it out and then copy it back? Too many steps to make mistakes - When submitting modifications, the comparison is also based on the browser's own solution, which is still inconvenient
- It is troublesome to trace back the historical version, it is inconvenient to retrieve, it cannot be compared, and there is a 30-day limit
- To increase the common configuration of all modules, all modules need to be modified accordingly to add
spring.cloud.nacos.config.shared-configs
configuration
Based on the above reasons, the new project decided to abandon nacos and use SpringCloud's native configuration center for the following reasons:
- Spring Cloud's configuration center, using git as a configuration data source
- Support gitlab, github, gitee, etc.
- Local files, easy to edit
- Git's version management mechanism, team management, submission, comparison, branch merging and other sound mechanisms
- Multiple default global configurations are supported:
application.yml
Affects all modules in all environmentsapplication-test.yml
All modules that affect the test environmentxxx.yml
The specified module of xxx that affects all environmentsxxx-test.yml
The specified module xxx that affects the test environment
Of course, nacos has an advantage that it integrates the configuration automatic refresh capability;
and SpringCloud's configuration center needs to integrate message middleware such as kafka or rabbitmq to have the configuration automatic refresh capability.
Let's introduce the use of Spring Cloud's configuration center.
This article is based on:
- IDEA2022.1.3
- SpringBoot 2.7.9
- SpringCloud 2021.0.6
- java 1.8
2. Build the configuration center server
1. Create a git configuration store
You can create a new project storage on git,
or create a new subdirectory in the existing git project, dedicated to storing all configurations.
I created a new directory in an existing project of gitee, called spring-configs
, and uploaded it in advance Several configuration files:
Note: In the actual test, it was found that github is basically not connected to the network, so use gitee to test
2. New project + Maven dependency
Create a new project in IDEA, configure the name, language, group, type, software package, JDK version, java version, etc.:
- Add maven dependencies
In the next step, select Spring Boot version 2.7.9 (because 3.x does not support Java1.8), and check the dependenciesConfig Server
Note: It is recommended to check the dependencies in the new project, and modify the pom.xml later. troublesome
3. Code and configuration modification
- Open
main
the class where the function is located and add annotations@EnableConfigServer
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class MyConfigServerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MyConfigServerDemoApplication.class, args);
}
}
- Delete in the resources directory
application.properties
and create a new fileapplication.yml
Note: I like the yml format, you can also edit it directlyapplication.properties
- Open
application.yml
, add git configuration:
server:
port: 8999 # 配置中心服务端在8999端口监听
spring:
application:
name: my-config-server-demo
# 配置完直接启动即可,访问方式:
# http://localhost:8999/{spring.application.name}/{spring.profiles.active}/{git分支}
# {spring.application.name} 必需,就是具体项目的项目名(yml里配置的),不是config-server的哦
# {spring.profiles.active} 必需,就是具体项目的环境(yml里配置的),注:具体项目可以不配置,使用默认值
# {git分支} 可空,git配置文件所在的分支,默认使用下面的default-label
#
# 注意:server项目启动后,会把git项目clone到本地,如windows系统会在 C:\Users\xxx\AppData\Local\Temp\config-repo-xxx
cloud:
config:
server:
git:
uri: https://gitee.com/youbl/my-demo.git # git项目的url地址,支持gitlab、github、gitee等
search-paths: spring-configs # git项目下,存放yml配置文件的子目录
username: beinet # git账号
password: 123456 # git密码
default-label: master # 默认会获取main分支,不存在就报错: No such label: main
timeout: 6 # 读取git的超时时间,默认5秒
#clone-on-start: true # 启动时把配置clone到本地,默认false,第一次访问会比较慢
#basedir: c:/abc # 本地默认工作目录
#refresh-rate: 100 # 服务从git更新配置的时间间隔,单位秒,默认值0,表示每次请求都去获取最新配置
skip-ssl-validation: true # 忽略git地址的ssl错误: unable to find valid certification path to requested target
OK, start
the above project under the preview of the project. After the startup is complete, visit the address: http://localhost:8999/config-client-demo/test
you can see a json similar to the following, listing all the yml files that the project will access, and their contents:
{
"name": "config-client-demo",
"profiles": [
"test"
],
"label": null,
"version": "169ff9974ccc09c594995ceabac26c983cd607bf",
"state": null,
"propertySources": [
{
"name": "https://gitee.com/youbl/my-demo.git/spring-configs/config-client-demo-test.yml",
"source": {
"beinet.config": "配置中心的front-study-test值",
"beinet.tttt": "abdefssadfga"
}
},
{
"name": "https://gitee.com/youbl/my-demo.git/spring-configs/application-test.yml",
"source": {
"beinet.config": "配置中心的全局-test值",
"beinet.tttt": "abdefs",
"beinet.newVal": "2惹2"
}
},
{
"name": "https://gitee.com/youbl/my-demo.git/spring-configs/config-client-demo.yml",
"source": {
"beinet.config": "配置中心的front-study默认值",
"beinet.tttt": "abdefs"
}
},
{
"name": "https://gitee.com/youbl/my-demo.git/spring-configs/application.yml",
"source": {
"beinet.config": "配置中心的全局值",
"beinet.tttt": "abdefs"
}
}
]
}
3. SpringBoot client connection access configuration center
After the configuration center server is built, the next step is to configure the client to connect and access the configuration of the configuration center.
1. Add maven dependency
- When creating a new project, on the dependency page, just check it
Config Client
to complete the dependency addition.
Note: For a new project, to open the pom, add the following dependencies:
<dependency> <!-- 用于加载bootstrap.yml配置,否则报错 No spring.config.import property has been defined -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
- If it is an old project, open the pom.xml file of the project and add the configuration:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.9</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency> <!-- 用于加载bootstrap.yml配置,否则报错 No spring.config.import property has been defined -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. Add bootstrap.yml
configuration
In the project resources
directory, create a new file bootstrap.yml
, content reference:
spring:
application:
name: config-client-demo # 项目名,配置中心读取配置用
cloud:
config:
uri: http://localhost:8999 # 指定配置中心的url
profile: test # 指定使用哪个配置,可以搭配spring.profiles.active使用
label: master # 指定分支,可为空,默认取主干
Note: If an error is reported: No spring.config.import property has been defined
confirm whether the Maven dependency is missingspring-cloud-starter-bootstrap
OK, start the client, and output the configuration written in the configuration center to
try. Test reference code:
package beinet.cn.configclientdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
@SpringBootApplication
public class ConfigClientDemoApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ConfigClientDemoApplication.class, args);
}
@Autowired
Environment env;
@Override
public void run(String... args) throws Exception {
System.out.println(env.getProperty("beinet.config"));
}
}
4. Client configuration refresh
After the client successfully connects to the configuration center, it can only read the configuration at startup.
If the configuration on git is modified, the client must be restarted to load the latest configuration.
Here is how to manually refresh the client configuration.
1. Add actuator dependency
Open the pom.xml of the client project config-client-demo
and add the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. Configuration modification
Open the client project config-client-demo
and bootstrap.yml
add the following configuration:
management:
endpoints:
web:
exposure:
include: "refresh" # 用*表示暴露全部
3. Add RefreshScope
annotations
Add annotations to classes that have read configuration and need to be refreshed RefreshScope
, such as:
@Component
@RefreshScope
public class ConfigTest2 {
@Value("${beinet.newVal}")
String str3;
public String getStr3() {
return str3;
}
}
4. Adjust the client interface and refresh the configuration
OK, when the configuration of the configuration center changes, the configuration refresh can be completed by manually calling the interface of the client: the
POST http://localhost:8080/actuator/refresh
corresponding CURL command: curl -X POST http://localhost:8080/actuator/refresh
after executing the interface request, you can see the log of the client, and there will be more logs for reloading the configuration, for example :
2023-03-22 13:38:37.976 INFO 2260 --- [nio-8080-exec-8] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8999
2023-03-22 13:38:38.844 INFO 2260 --- [nio-8080-exec-8] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=config-client-demo, profiles=[test], label=master, version=e5b67cb61ad976c2c1bd863dae769aabf1553c21, state=null
2023-03-22 13:38:38.844 INFO 2260 --- [nio-8080-exec-8] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-configClient'}, BootstrapPropertySource {name='bootstrapProperties-https://gitee.com/youbl/my-demo.git/spring-configs/config-client-demo-test.yml'}, BootstrapPropertySource {name='bootstrapProperties-https://gitee.com/youbl/my-demo.git/spring-configs/application-test.yml'}, BootstrapPropertySource {name='bootstrapProperties-https://gitee.com/youbl/my-demo.git/spring-configs/config-client-demo.yml'}, BootstrapPropertySource {name='bootstrapProperties-https://gitee.com/youbl/my-demo.git/spring-configs/application.yml'}]
2023-03-22 13:38:38.846 INFO 2260 --- [nio-8080-exec-8] o.s.boot.SpringApplication : No active profile set, falling back to 1 default profile: "default"
2023-03-22 13:38:38.849 INFO 2260 --- [nio-8080-exec-8] o.s.boot.SpringApplication : Started application in 0.998 seconds (JVM running for 402.306)
配置中心的front-study-test值..
5. Refresh the notes
- The passed
Environment
Bean reads the configuration and will be refreshed RefreshScope
Configurations without annotations will not be refreshed- The class where the main function is located will not be refreshed, even if it is
RefreshScope
added
5. Automatically refresh all client configurations through the bus message bus
The above method can only refresh the configuration of a single client, and will not refresh the configuration of other services.
Even if a service deploys multiple machines, other machines will not be refreshed.
You need to know which machines each service is deployed on, and call interface refresh one machine at a time.
In this section, we will introduce how to notify all clients on the server side of the configuration center to automatically refresh the configuration.
Principle description:
- Call the API of the configuration center server to notify the refresh
- Configure the central server to deliver messages to Kafka
- All clients listen to Kafka messages and perform refresh configuration
1. Add dependencies and configuration on the server side
- Open the configuration center server
pom.xml
and add the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-kafka</artifactId>
</dependency>
- Open the configuration center server
application.yml
, add the following configuration, and enable bus message push:
spring:
cloud:
# 启用bus后,对应的消息队列(如kafka)会自动创建一个topic springCloudBus
# 使用 curl -X POST http://localhost:8999/actuator/busrefresh 会触发消息推送到这个topic,供client使用
bus:
refresh:
enabled: true
kafka:
bootstrap-servers: 10.1.2.3:9092 # 用到的Kafka连接信息
management:
endpoints:
web:
exposure:
include: "busrefresh" # 用*表示暴露全部
OK, you can start the configuration center server.
2. The client adds dependencies and configurations
- Open each client
pom.xml
and add the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-kafka</artifactId>
</dependency>
- Open each client
bootstrap.yml
, add kafka configuration, and enable bus message consumption:
spring:
kafka:
bootstrap-servers: 10.1.2.3:9092 # 用到的Kafka连接信息
OK, let's start these clients.
3. Adjust the server interface and refresh all client configurations
OK, when the configuration of the configuration center is changed,
it is still necessary to call the interface manually, but the interface of the server is called to complete the configuration refresh of all clients: the
POST http://localhost:8999/actuator/busrefresh
corresponding CURL command:curl -X POST http://localhost:8999/actuator/busrefresh
After executing the interface request, you can see that the server and each client will have more logs for reloading the configuration
Finally, the original configuration center is not good at this point. If you change the configuration, you must manually adjust the interface to refresh it.