学习目标
本文所讲内容为上一文的后续,我们在上一文中学习了什么是 Spring Cloud 的配置服务器;如何使用两种方式搭建 Spring Cloud Config Server 以及客户端如何连接配置服务器。本文将以问题解答的形式一步步讲解如何刷新配置,所用示例项目仍为上文所用代码:
- spring-cloud-chapter-3-config-server 端口:9090
- spring-cloud-chapter-3-config-client 端口:8080
动态配置属性 Bean
当我们的服务发布到了服务器上后,我们想要修改配置文件中的某些配置,我们该怎么办呢?有些小伙伴就会说:“把服务停掉,修改配置文件后重新启动不就解决了”。的确,这是一种解决办法,但是并不是一种好的解决办法,停掉服务器会对用户产生很大的影响,尤其是在单体应用中,你把服务器停掉,别人就无法访问,客户就抓狂了,你的客服同事也会恨死你。那么这里我们就讲解一下如何动态配置,让服务正常运行的同时,修改配置信息。
1)在 spring-cloud-chapter-3-config-client
项目中定义配置属性 Bean User
,此处使用了 @ConfigurationProperties(prefix = "xxx")
注解。
package top.alanshelby.springcloudchapter3configclient.domain;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "as.user")
public class User {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2)创建 UserController
,并使用构造器的方式注入 User
对象,使用 @EnableConfigurationProperties(User.class)
注解。
package top.alanshelby.springcloudchapter3configclient.web.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import top.alanshelby.springcloudchapter3configclient.domain.User;
@RestController
@EnableConfigurationProperties(User.class)
public class UserController {
private final User user;
@Autowired
public UserController(User user) {
this.user = user;
}
@GetMapping("/user")
public User user() {
return user;
}
}
3)将 User
关联配置项,在 application.properties
中进行配置
as.user.id = 1
as.user.name = AlanShelby
通过浏览器访问:http://localhost:8080/env/as.user.*
{
"as.user.name":"AlanShelby",
"as.user.id":"1"
}
可以看到我们的配置已经生效了,准备工作一切就绪,那么我们应该如何动态修改配置信息呢?这里我们需要借助 PostMan 工具来进行修改。
4)配置完成后,可以使用 PostMan 发送 POST
请求可动态修改参数信息
- 请求:http://localhost:8080/env
- 请求类型:POST
- 参数:
- as.user.name -> spring-cloud
- as.user.id -> 2
修改完成后,重新通过浏览器访问:http://localhost:8080/env/as.user.*,可以看到配置信息已经修改过来了,这样就实现了在不重启服务的前提下修改配置信息。
{
"as.user.name":"spring-cloud",
"as.user.id":"2"
}
说到这,不知道小伙伴们有没有什么疑问。我们所讲的内容为微服务方面的知识,也就是说不可能仅仅只有一个服务发布,如果在整个微服务项目中有几十个或者几百个服务实例,难道我们要手动挨个进行修改吗?不存在的,那样我们程序猿们早就撂挑子不干了,所以我们要想一个办法,能够调整所有机器的配置,那我们应该如何做呢?接下来,我们来一起解决这个问题。
问题:如果需要调整所有机器的配置应该如何操做?
解决这个问题前,我们要先搞明白一些事情,在上一文中我们讲了如何搭建 Spring Cloud Config Server,我们讲解了两种方式,这里我们要了解的是配置客户端应用所关联的分布式配置信息,优先于传统的配置信息,如 application.properties
(application.yml
)或者是 bootstrap.properties
(bootstrap.yml
),由此可知,要解决这个问题,我们可以对配置服务器配置信息进行调整(blogstemp-prod.properties
)。
启动 spring-cloud-chapter-3-config-server
项目,服务端启动完毕后重启 spring-cloud-chapter-3-config-client
项目
注意:
blogstemp-prod.properties
为上文中基于远程 git 仓库使用的配置文件,这里依旧使用它作为例子。
1)在 blogstemp-prod.properties
文件中添加如下信息:
as.user.id = 1000
as.user.name = AlanShelbyTest
修改完成后,将代码提交到 GitHub,访问:http://localhost:9090/blogstemp/prod,即可发现服务端配置信息就改过来了。
但是当我们访问客户端时:http://localhost:8080/env,就会发现,客户端并没有及时把服务端的配置信息同步过来,那这个应该如何解决呢?
这里我们可以使用 Spring Cloud 给我们提供的 refresh
端点来进行刷新操作,依旧使用 PostMan 进行操作:
- 请求:http://localhost:8080/refresh
- 请求类型:
POST
请求完成后,会返回给我们修改的配置 key:
[
"as.user.id",
"config.client.version",
"as.user.name"
]
重新访问 http://localhost:8080/env,就会发现我们刚刚修改的配置已经同步过来了。
这样修改的分布式配置信息就可以应用于所有服务实例了,是不是一举多得。
客户端调整所有机器的配置的问题解决了,那么新的问题又出现了。我们刚刚使用了 Spring Cloud 给我们提供的 refresh
端点手动为客户端刷新了远程配置信息,这样很不方便,每次修改完信息后,都要有专门的人员来进行刷新操作,十分不友好,那么我们如何让服务端更新配置信息后,客户端进行感知后自动刷新呢?接下来我们就来解决一下这个问题。
问题:如果服务端更新了,客户端如何感知?
从上面我们已经知道了可以使用 Spring Cloud 给我们提供的 refresh
端点手动进行刷新操作,客户端感知说白了就是客户端定时刷新,所以我们使用一个简易的定时任务就可以解决这个问题,这种方式只是一种解决办法,较为简单、方便,还有很多其他的解决方式(如官方文档中提供的整合 Spring Cloud Bus 和 spring-cloud-config-monitor),这里只是提供解决思路,读者可自行斟酌使用。
1)使用构造器注入的方式将 ContextRefresher
进行注入,使用定时任务每5秒(根据需求自行设定)对上下文进行一次刷新,这里使用了 contextRefresher.refresh()
进行刷新。
package top.alanshelby.springcloudchapter3configclient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.scheduling.annotation.Scheduled;
import java.util.Set;
@SpringBootApplication
public class SpringCloudChapter3ConfigClientApplication {
private final ContextRefresher contextRefresher;
// 使用构造器注入的方式将 contextRefresher 进行注入
@Autowired
public SpringCloudChapter3ConfigClientApplication(ContextRefresher contextRefresher) {
this.contextRefresher = contextRefresher;
}
@Scheduled(fixedRate = 5000L)
public void update() {
Set<String> keys = contextRefresher.refresh();
if (!keys.isEmpty()) {
System.out.println("本次更新的配置项:" + keys);
}
}
public static void main(String[] args) {
SpringApplication.run(SpringCloudChapter3ConfigClientApplication.class, args);
}
}
2)修改 blogstemp-prod.properties
配置文件,并提交到远程 GitHub 仓库
as.user.id = 1001
as.user.name = Shelby
3)查看日志信息,可以看到输入如下信息,表明上下文的刷新操作完成:
本次更新的配置项:[as.user.id, config.client.version, as.user.name]
至此,关于Spring Cloud Config Server(配置服务器)所有内容就讲解完了,这是我的理解,各位看官如果有不同见解或文章中有错误,请不吝指正。
所用代码码云地址:https://gitee.com/AlanShelby/spring-cloud-chapter
知乎专栏地址:https://zhuanlan.zhihu.com/c_200981602
个人微信公众号:AlanShelby(多多关注,感谢~)