One, configuration center
Why do you need a configuration center
For a single application, the configuration is written in the configuration file, there is no big problem. If you want to switch the environment, you can switch between different profiles (2 ways), but in microservices, there are more microservices. Hundreds and thousands of configurations require centralized management, management of configurations in different environments, dynamic adjustment of configuration parameters, and continuous service changes.
Introduction to Configuration Center
The distributed configuration center consists of 3 parts:
- Places to store configuration: git, svn, database, local files, etc.
- config server, read the configuration from 1.
- config client. It is the client consumption configuration of the config server.
Note: The configuration will not be updated by itself, and it is necessary to trigger the client before going to git to pull it. Or trigger to view the configuration on config-server, then go to git to pull it.
Second, use
Below we integrate Spring Cloud Config in the Spring Boot project, and use github as the configuration storage, mainly from the following two parts to demonstrate:
- Built out of Eureka's configuration center.
- The configuration center of Eureka is built.
Configuration file preparation:
We put the following four configuration files on github: Configuration center warehouse address
config-single-client-dev.yml
data:
env: sinle-client-env
user:
username: bobo1
password: 123
config-single-client-prod.yml
data:
env: sinle-client-prod
user:
username: bobo2
password: 1234
config-eureka-client-dev.yml
data:
env: eureka-client-env
user:
username: bobo3
password: 12345
config-eureka-client-prod.yml
data:
env: eureka-client-prod
user:
username: bobo4
password: 123456
1. Set up without Eureka's configuration center
The simplest configuration center is to start a service as a server, and then each service that needs to obtain configuration as a client to this server to obtain the configuration.
Create configuration center server
1. Create a new model, config-single-server, import web and config-server dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2, placement application.yml
server:
port: 7001
spring:
application:
name: config-single-server
cloud:
config:
server:
git:
# 配置文件仓库地址
uri: https://github.com/zhaosongbobo/spring-cloud-config-test
username: github帐号
password: github密码
# 配置文件主干
default-label: master
# 跳过ssl检查
skip-ssl-validation: true
# 配置文件保存的本地机器的目录
basedir: /home/bobo/config
3. Add @EnableConfigServer annotation to the startup class
@SpringBootApplication
@EnableConfigServer
public class ConfigSingleServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigSingleServerApplication.class, args);
}
}
4. Start config-single-server verification
Spring Cloud Config has its own set of access rules, and we can access it directly on the browser through this set of rules.
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
- {application} is the application name, which corresponds to the configuration file, which is the spring.application.name value of the configuration file .
- {profile} is the version of the configuration file. Our project has a development version, a test environment version, and a production environment version. Corresponding to the configuration file, it is distinguished by application-{profile}.yml, such as application-dev.yml, application- sit.yml, application-prod.yml.
- {label} represents the git branch. The default is the master branch. If the project is distinguished by branch, it is possible to control access to different configuration files through different labels.
We follow the above rules to access the server we just started:
http://localhost:7001/config-single-client/dev/master
http://localhost:7001/config-single-client-dev.yml
http://localhost:7001/master/config-single-client-dev.yml
The output is as follows:
By visiting the above address, if the data can be returned normally, it means that everything is normal on the server side of the configuration center.
Create a configuration center client
The configuration center server is ready and the configuration data is ready. Next, we will use it in our project.
1. Create model, config-single-client, and import web, config dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
2. Configure the bootstrap.yml and application.yml configuration files
bootstrap.yml
spring:
application:
name: config-single-client
cloud:
config:
uri: http://localhost:7001
profile: dev
label: master
profiles:
active: dev
Note: Why use bootstrap configuration file here?
This is determined by the priority of loading the property file of spring boot. If you want to fetch the configuration file from the spring cloud config server before loading the properties, the spring cloud config related configuration needs to be loaded first, and the bootstrap.yaml Loading is before application.yaml, so the config client can only write the relevant configuration of config in bootstrap.properties.
application.yml
server:
port: 7008
3. Read the content of the configuration file, generally obtained through @Value or @ConfigurationProperties
@Component
@Data
public class GitConfig {
@Value("${data.env}")
private String env;
@Value("${data.user.username}")
private String username;
@Value("${data.user.password}")
private String password;
}
@Component
@Data
@ConfigurationProperties(prefix = "data")
public class GitAutoRefreshConfig {
private String env;
private UserInfo user;
@Data
public static class UserInfo {
private String username;
private String password;
}
}
4. GitController to test the configuration
@RestController
public class GitController {
@Autowired
private GitConfig gitConfig;
@Autowired
private GitAutoRefreshConfig gitAutoRefreshConfig;
@GetMapping("/getInfo")
public Object getInfo(){
return gitConfig;
}
@GetMapping("/getAutoInfo")
public Object getAutoInfo(){
return gitAutoRefreshConfig;
}
}
5. Results
2. Integrate Eureka's configuration center to build
If Eureka is used as a service registration discovery center in our system, Spring Cloud Config should also be registered on Eureka to facilitate the use of other service consumers, and multiple configuration center servers can be registered to achieve high availability.
Okay, let's integrate Spring Cloud Config to Eureka.
Create Eureka server
1. Create a new model, eureka-server, and configure pom dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2, placement eureka, application.yml
spring:
application:
name: eureka-server
eureka:
client:
service-url:
defaultZone: http://euk-server1:8001/eureka/
instance:
hostname: euk-server1
server:
port: 8001
3. Add @EnableEurekaServer annotation to the startup class
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Create the configuration center server and register it to EurekaServer
1. Create new model, config-eureka-server, add pom dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2. Configure eureka and config application.yml
server:
port: 8002
spring:
application:
name: config-eureka-server
cloud:
config:
server:
git:
uri: https://github.com/zhaosongbobo/spring-cloud-config-test
username: github帐号
password: github密码
default-label: master
skip-ssl-validation: true
basedir: /home/bobo/config
eureka:
instance:
hostname: euk-server2
client:
service-url:
defaultZone: http://euk-server1:8001/eureka
3. Add @EnableConfigServer and @EnableEurekaClient annotations to the startup class
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigEurekaServerApplication.class, args);
}
}
4. Start config-eureka-sever and verify that the configuration is successful
Create a configuration center client
The configuration of the client has relatively changed a bit. After joining Eureka, there is no need to directly deal with the configuration center server, but to access it through Eureka. In addition, pay attention to the application name of the client to be consistent with the name of the configuration file in github.
1. Create new model, config-eureka-client, add pom dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2. Configure bootstrap.yaml and application.yaml
bootstrap.yml
spring:
application:
name: config-eureka-client
cloud:
config:
discovery:
enabled: true
# 指定配置中心服务端的server-id
service-id: config-eureka-server
# 指定仓库主干
label: master
# 指定版本
profile: dev
eureka:
client:
service-url:
defaultZone: http://euk-server1:8001/eureka/
application.yml
server:
port: 8003
In addition to the configuration registered to Eureka, the configuration is to establish a relationship with the configuration center server.
The service-id is the application name of the server.
Note: Why use bootstrap configuration file here?
This is determined by the priority of loading the property file of spring boot. If you want to fetch the configuration file from the spring cloud config server before loading the properties, the spring cloud config related configuration needs to be loaded first, and the bootstrap.yaml Loading is before application.yaml, so the config client can only write the relevant configuration of config in bootstrap.properties.
3. Read the content of the configuration file, generally obtained through @Value or @ConfigurationProperties
Take it directly from the above example without any changes:
@Component
@Data
public class GitConfig {
@Value("${data.env}")
private String env;
@Value("${data.user.username}")
private String username;
@Value("${data.user.password}")
private String password;
}
@Component
@Data
@ConfigurationProperties(prefix = "data")
public class GitAutoRefreshConfig {
private String env;
private UserInfo user;
@Data
public static class UserInfo {
private String username;
private String password;
}
}
4. GitController to test the configuration
@RestController
public class GitController {
@Autowired
private GitConfig gitConfig;
@Autowired
private GitAutoRefreshConfig gitAutoRefreshConfig;
@GetMapping("/getInfo")
public Object getInfo(){
return gitConfig;
}
@GetMapping("/getAutoInfo")
public Object getAutoInfo(){
return gitAutoRefreshConfig;
}
}
5. Startup class
@SpringBootApplication
@EnableDiscoveryClient
public class ConfigEurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigEurekaClientApplication.class, args);
}
}
6. Results
Three, manual refresh
The mechanism of Spring Cloud Config to load configuration content when the project starts has a defect that it will not automatically refresh after modifying the content of the configuration file. For example, in our project above, when the service has started, modify the content of the configuration file on github. At this time, refresh the page again. Sorry, it is the old configuration content, and the new content will not be refreshed actively.
However, you can't restart the service every time you modify the configuration. If that's the case, it's better not to use it. Wouldn't it be faster to use the local configuration file directly.
It provides a refresh mechanism, but we need to trigger it actively. That is @RefreshScope annotation combined with actuator, pay attention to the introduction of the spring-boot-starter-actuator package.
1. Add a dependency actuator to the pom dependency of config-eureka-client
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2. Add actuator configuration in config client configuration
application.yml
server:
port: 8003
management:
endpoint:
shutdown:
enabled: false
endpoints:
web:
exposure:
include: "*"
2. Add the @RefreshScope annotation to the class that needs to read the configuration. We use the configuration in the controller, so add it to the controller.
@RestController
@RefreshScope
public class GitController {
@Autowired
private GitConfig gitConfig;
@Autowired
private GitAutoRefreshConfig gitAutoRefreshConfig;
@GetMapping("/getInfo")
public Object getInfo(){
return gitConfig;
}
@GetMapping("/getAutoInfo")
public Object getAutoInfo(){
return gitAutoRefreshConfig;
}
}
Note that the above are all modifications made on the client side.
After that, restart the client. After restarting, we modify the configuration file config-eureka-client-dev.yml on github
original:
data:
env: eureka-client-env
user:
username: bobo3
password: 12345
After modification:
data:
env: eureka-client-env
user:
username: bobo3修改111
password: 12345
Refresh the page again, nothing happens.
Next, we send a POST request to the http://localhost:8003/actuator/refresh interface, using tools such as postman, this interface is used to trigger the loading of the new configuration, and the returned content is as follows:
After that, visit the RESTful interface again, http://localhost:8003/getAutoInfo
You can see that the data obtained by this interface is up to date, indicating that the refresh mechanism is working.
But when we visit http://localhost:8003/getInfo, we still get the old data, which is related to the implementation of the @Value annotation, so we should not use this method to load the configuration in the project.
Change to automatic refresh
Github provides a webhook method. When there is a code change, it will call the address we set to achieve the purpose we want to achieve.
1. Enter the github warehouse configuration page, select Webhooks, and click add webhook
2. Then fill in the address of the callback, which is the address mentioned above http://localhost:8003/actuator/refresh, but it must be ensured that this address is accessible by github. If it is an intranet, there is no way. This is just a demonstration. Generally, projects in the company will have their own code management tools, such as self-built gitlab. Gitlab also has the function of webhook, so that you can call the address of the intranet.
Four, automatic refresh
Use Spring Cloud Bus to automatically refresh multiple terminals:
Spring Cloud Bus 将分布式系统的节点与轻量级消息代理链接。这可以用于广播状态更改(例如配置更改)或其他管理指令。一个关键的想法是,Bus 就像一个扩展的 Spring Boot 应用程序的分布式执行器,但也可以用作应用程序之间的通信渠道。
—— Spring Cloud Bus 官方解释
No introduction here, you can refer to this article to achieve:
Spring Cloud Tutorial-Use Spring Cloud Bus to automatically refresh configuration changes
Five, write to the end
Here is such a problem when using the client to pull the configuration, here is the emphasis:
我用spring boot 2.4.1和spring cloud 2020.0.0-RC1版本去获取配置时获取不到。
把版本改为spring boot 2.3.4.RELEASE 和 spring cloud Hoxton.SR8版本获取配置正常
暂时不清楚为什么,可能新的版本有了变化,如果大家知道原因的话可以在评论区留言告知!!!
The examples used in this article have been uploaded to the code cloud: