“This is the 15th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
1, the introduction of
Pain points of traditional configuration:
- In previous projects, we configured Java projects through configuration files, operating system variables, Java system properties, and so on. After the Spring Boot explosion, our configuration information is written in application.yml or application.properties files, which are distributed along with the project packaging and application; However, when we need to modify the configuration information in the configuration file, we need to update the configuration file to rebuild and publish. If the configuration information is configured in operating system environment variables or Java system properties, restart the application.
- Configuration files often contain some sensitive information, such as database passwords, Redis passwords, encryption keys and other information. If the information is directly configured in the configuration file, it is easy to leak.
Spring Cloud’s early release of Spring Cloud Config for centralized configuration management addressed these issues successfully.
Spring Cloud Config is divided into Server side and Client side. The Spring Cloud Config Server is a service provided by Spring Cloud to provide centralized configuration for all services in a specified application. With the help of Spring Cloud Config Server, the configuration of all applications can be centrally managed to avoid repeated configuration.
Spring Cloud Config brings many benefits:
- The configuration file is decoupled from the application. The configuration file can be updated, published, or rolled back at any time without restarting the application
- Different services can share configurations, which is very useful in microservice architecture systems to avoid repeated configurations and greatly reduce the maintenance cost of microservice configurations
- After application isolation is configured, sensitive information is protected
Spring Cloud Config Server provides configuration properties for microservices via Git repository:
2, the body
Spring Cloud Config is discussed through the Spring Boot project. There will be the following aspects:
- Spring Cloud Config + Git manual refresh
- Spring Cloud Config + Git + WebHook automatic refresh
- Spring Cloud Config + Eureka
- Spring Cloud Bus multistage refresh
Note that the entire project is built step by step, and that repeated steps are not repeated.
2.1 Spring Cloud Config + Manual refresh
Spring Cloud Config Server
The Spring Cloud Config Server service should be run and maintained as a separate application, so we start a separate service for the Spring Cloud Config Server.
Rely on:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Copy the code
The Spring Boot and Spring Cloud versions I selected are as follows (if the versions do not correspond, there will be an exception, you can choose the corresponding version you need) :
<! RELEASE--> <parent> <groupId>org.springframework.boot</groupId> The < artifactId > spring - the boot - starter - parent < / artifactId > < version > 2.3.4. RELEASE < / version > < / parent > <! <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>>Hoxton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>Copy the code
Application. Yml configuration file:
There are several important points in the configuration file below, and configuration information cannot be obtained if the configuration is incorrect
A, default-label: indicates the branch where the configuration file resides. The default value is master
B. Search-paths: indicates the root directory where the configuration file resides
C, URI, warehouse address
Cloud: config: server: git: uri: https://gitee.com/leonplious/config-server-demo.git # warehouse address username: XXXX # git login account password: Paths: userService # root folder name ## server: port: 28888Copy the code
Write a startup class that requires the @enableconFigServer annotation
@SpringBootApplication @EnableConfigServer public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code
At this point we can start testing the Spring Cloud Config Server. Push a configuration file named userservice-dev.yml to git repository.
user:
username: "liziba"
password: "hello"
Copy the code
Start the Spring Cloud Config Server application, visit http://localhost:28888/userservice/dev/master, you can get the following information, The Spring Cloud Config Server service is successfully started.
{
"name":"userservice",
"profiles":[
"dev"
],
"label":"master",
"version":"285fd1b9f068cec6def6ba14ab787807a9ffecbc",
"state":null,
"propertySources":[
{
"name":"https://gitee.com/leonplious/config-server-demo.git/userservice/userservice-dev.yml",
"source":{
"user.username":"liziba",
"user.password":"hello"
}
}
]
}
Copy the code
Note that Spring Cloud Config has its own set of access rules that allow you to retrieve the data in a slightly different response format.
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
Copy the code
- Application indicates the name of the application. The name of the configuration file should be strictly named application-{profile}.yml.
- Profile refers to environment information, such as production environment [PROd], development environment [dev], and test environment [test].
- Label refers to a Git branch, such as master
I use the first method here, which returns detailed configuration information, as well as branch information, profile information, application name, etc. The default branch name master can be omitted. http://localhost:28888/userservice/dev is equivalent to http://localhost:28888/userservice/dev/master
Now you can start configuring the Spring Cloud Config Client
Create the Spring Cloud Config Client service, which gets the configuration information from the Spring Cloud Config Server.
Rely on:
<! - config depend on client - > < the 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> <! -- BSactuator updates endpoints --> <dependency> <groupId> org.springFramework. boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>Copy the code
Configuration file bootstrap.yml:
Notice When you use config to obtain configuration information, you need to extract the config configuration to the bootstrap.yml configuration file with the highest priority; otherwise, the configuration will not take effect. Spring-cloud-starter-config accesses port 8888 by default. If your Spring Cloud Config Server is not started with this port, You can specify the Spring Cloud Config Server port information in the bootstrap.yml file so that it can be overridden; otherwise, the configuration information on the Spring Cloud Config Server cannot be obtained.
My configuration file here demonstrates multi-environment dev and prod. Note that my config.uri address is http://localhost:28888, not http://localhost:8888
Server: port: 18888 Spring: Application: name: UserService profiles: active: dev ## Load and expose all endpoints to refresh endpoint management: Endpoints: refresh: enabled: true Web: exposure: include: '*' NaN --- spring: profiles: dev cloud: config: uri: http://localhost:28888 label: master profile: dev fail-fast: true --- spring: profiles: prod cloud: config: uri: http://localhost:28888 label: master profile: prod fail-fast: trueCopy the code
Write two User and User2 classes to get configuration information, using @Value or @configurationProperties, respectively:
@Data
@ToString
@Component
public class User {
@Value("${user.username}")
private String username;
@Value("${user.password}")
private String password;
}
Copy the code
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "user")
public class User2 {
private String username;
private String password;
}
Copy the code
Write a REST access endpoint to get configuration information for two users:
@RequiredArgsConstructor
@RestController
@RequestMapping("/user")
public class UserController {
private final User user;
private final User2 user2;
@GetMapping("/user1")
public String user() {
return user.toString();
}
@GetMapping("/user2")
public String user2() {
return user2.toString();
}
}
Copy the code
Start the service, access the two REST endpoints, and obtain the following information, indicating that the configuration information has been obtained.
http://localhost:18888/user/user1
User(username=liziba, password=hello)
Copy the code
http://localhost:18888/user/user2
User2(username=liziba, password=hello)
Copy the code
At this point, we change username to Chinese ‘Plum EIGHT’ and push it to Gitee. The modified configuration file is as follows:
User: username: "Leo" password: "hello"Copy the code
Revisiting both REST endpoints, both requests return old data and do not get the latest configuration. Don’t panic, no one told him to update it. It must be old data! This is where the actuator dependencies and management. Endpoints configuration that we introduced come in handy.
We can with the tools of the postman, curl HTTP endpoint launched a post request to http://localhost:18888/actuator/refresh.
Access the two REST endpoints again and return the following data, respectively
http://localhost:18888/user/user1
User(username=liziba, password=hello)
Copy the code
http://localhost:18888/user/user2
User2(username= Leo EIGHT, password=hello)Copy the code
@Value gets the configuration information in a way that doesn’t get the latest data, and @ConfigurationProperties gets the configuration information in a way that gets the updated data, So remember to use @ConfigurationProperties in conjunction with Config to get configuration information during development.
2.2 Spring Cloud Config + Git + WebHook automatic refresh
To implement auto-refresh, we need two things; The first is the WebHook functionality provided by GitHub, Gitee, and GitLab, and the second is the @refreshScope annotation.
Step 1: Configure WebHook (I’m using Gitee here)
Go to the repository where your configuration file is located, select WebHooks from the Admin TAB, and click Add WebHooks
Note that the URL is filled with the Refresh endpoint provided by the Actuator, which is the address requested by postman above. You can select the event that you need to trigger the call to that address, usually using Push. It is particularly important to note that if you want Gitee or GitHub to provide a public address, GitLab code repository will be set up inside the company, and Intranet address can be used inside the company.
Step 2: Add the @refreshScope annotation
@RequiredArgsConstructor
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {
// ...
}
Copy the code
2.3 Spring Cloud Config + Eureka
In most cases, we use the configuration center in the microserver environment. Here we use the Eureka configuration center, combined with Spring Cloud Config for dynamic configuration refresh. To do this we need to introduce Eureka dependencies, start a registry service, and modify the Spring Cloud Config Server and Spring Cloud Config Client configurations.
Rely on:
<! - Eureka Server rely on - > < the dependency > < groupId > org. Springframework. Cloud < / groupId > <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>Copy the code
Configuration file:
server:
port: 8888
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
Copy the code
Start the class:
@SpringBootApplication @EnableEurekaServer public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code
Modify Spring Cloud Config Server
Increase dependence:
<! - Eureka Client depend on - > < the dependency > < groupId > org. Springframework. Cloud < / groupId > <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>Copy the code
Modify the configuration file (add the Eureka client configuration) :
spring:
application:
name: config-service
cloud:
config:
server:
git:
uri: https://gitee.com/leonplious/config-server-demo.git
username: xxxx
password: xxxx
default-label: master
search-paths: userservice
server:
port: 28888
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://localhost:8888/eureka/
instance:
prefer-ip-address: true
Copy the code
Modify the startup class (add @enableeurekaclient annotation) :
@SpringBootApplication @EnableConfigServer @EnableEurekaClient public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code
At this time, start EurekaServer and Spring Cloud Config Server, and you can see the Spring Cloud Config Server registration information on Eureka.
Modify the Spring Cloud Config Client
Increase dependence:
<! - Eureka Client depend on - > < the dependency > < groupId > org. Springframework. Cloud < / groupId > <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>Copy the code
Modify the configuration file (add eureka client configuration and modify Config configuration information) :
Without the registry we specify the URI, and with the registry we can use the service name directly.
server: port: 18888 spring: application: name: userservice profiles: active: dev eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8888/eureka instance: prefer-ip-address: Web: Exposure: include: '*' ## username: NaN password: NaN --- spring: profiles: dev cloud: config: discovery: enabled: true service-id: # uri: http://localhost:28888 label: master profile: dev fail-fast: true --- spring: profiles: prod cloud: config: discovery: enabled: true service-id: config-service # uri: http://localhost:28888 label: master profile: prod fail-fast: trueCopy the code
Modify the startup class (add @enableeurekaclient annotation) :
@SpringBootApplication @EnableEurekaClient public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code
Revisiting both REST endpoints can have the same effect. If you need to configure Eureka’s high availability cluster, you can refer to this article in my Spring Cloud series.
2.4 Spring Cloud Bus Multi-terminal Refresh
In a production environment, where we tend to cluster deployment, using WebHook to refresh a single endpoint is not a good idea. At this point we can use the Spring Cloud Bus to implement a multi-terminal refresh. This is done by broadcasting configuration update notifications through the Message Queue.
Official Address:
Spring. IO/projects/sp…
We will install RabbitMQ to use Spring Cloud Bus.
Modify the configuration and dependencies in the Spring Cloud Config Client application
Rely on:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
Copy the code
Modify the configuration file (reference the Rabbit configuration, other configurations remain unchanged) :
server:
port: 18888
spring:
application:
name: userservice
profiles:
active: dev
rabbitmq:
host: localhost
port: 5672
password: guest
username: guest
virtual-host: /
Copy the code
At this point, we use IDEA to start two services using different ports of the Spring Cloud Config Client application
Select the service and click Edit Configurations…
Modify the configuration, specify the port and service name, and select Allow Parallel Run
Make a copy of the configuration and start using another port
At this point, you can access the single point Eureka to view the registration information
RabbitMQ has two anonymous queues
At this point we access the REST port based on a different port
http://localhost:19999/user/user2
http://localhost:18888/user/user2
User2(username=liziba, password=123456)
Copy the code
Modify the configuration file on Gitee
user:
username: "Edg"
password: "champion"
Copy the code
If there is no use the postman configuration WebHook launched a post request to http://localhost:18888/actuator/bus-refresh endpoint, note that there is a bus – refresh. Revisit the two REST endpoints with the configuration information refreshed: