持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情
22、集群配置中心例子
二、集群配置中心例子
5、目录配置总结 -- 鸡肋
前面的小节对服务器与客户端的配置进行了简单的演示,如果读者对相关的目录配置有所疑问,可以阅读本小节。配置服务器和客户端,主要有与 以下几个目录相关的配置。
- 服务器 spring.cloud.config server.svn.uri = https://localhost/svn/test-project
- 服务器 pring.cloud.config.server.default-label = default-config
- 客户端 spring.application.name = spring-book-service
- 客户端 spring.cloud.config.profile = dev
从以上的4个配置中不难看出,服务器的两个配置用于指定到 SVN 的路径、配置目录,而客户端的两个配置则用于指定读取哪份配置文件。根据以上配置,客户端将会去 https:// localhost/svn/test-project/default-config 目录下读取名称为 spring-book-service-dev.yml 的文件。 如果客户端想指定目录,可以通过配置 spring.cloud.config.label = book-module 实现,配置后,客户端将会去 https: // localhost/svn/tes t-project/book-module 下读取配置文件。
另外,在实际环境中有可能存在多份配置文件,例如一份文件是专门配置 Hystrix 的,另一份是专门配置 Zuul的, 可以配置为 spring .cloud.config .profile = hystrix, zuul ,此时,将会去读取名称为 spring-book-service -hystrix.yml 与 spring-book-service-zuul.yml 的配置文件。
6、刷新配置
远程 SVN 服务器上面的配置修改后,需要通知客户端来改变配置。可以访问客户端的 /refresh 端点进行刷新, 访问该端点要使用 HTTP 的 POST 方法。修改 SVN 上面的 first-test.properties ,将 test. user.name 修改为 Songrongliang,再使用 HttpClient 来发送请求,刷新配置。发送 POST 请求的代码请见代码清单:
@RestController
public class RefreshController {
/**
* 刷新配置 由POST 改成 GET ,可以使用浏览器直接刷新,
* 不能再使用 http://localhost:8080/refresh 路径 Request method 'GET' not supported
* 因为当前Controller 优先级没有系统的高
*/
@RequestMapping(value = "/getRefresh")
public String refresh() throws IOException {
// 创建默认的 HttpClient
CloseableHttpClient httpClient = HttpClients.createDefault();
// 调用 Post 方法请求服务
HttpPost httpPost = new HttpPost("http://localhost:8080/refresh");
// 获取响应
HttpResponse response = httpClient.execute(httpPost);
// 根据响应解析出字符串
String entity = EntityUtils.toString(response.getEntity());
System.out.println(entity);
//java.io.IOException: Attempted read from closed stream.
//原因是EntityUtils.toString(HttpEntity)方法被使用了多次。所以每个方法内只能使用一次。
return entity;
}
}
修改配置并提交到 SVN 服务器后再运行代码清单 访问http://localhost:8080/getRefresh,可以看到控制台输出如下:
["config.client.version","test.user.name"]
客户端的 refresh 服务在接收到请求后,会重新到配置服务器获取最新的配置,然后用最新的配置与旧配置进行对比, 最终将有修改的配置 key 返回给服务调用者。在整个过程中,配置服务器、客户端都不需要重新启动,调用 refresh 刷新配置后,可以再访问客户端来查看配置是否更新。在浏览器中访问 http://localhost: 8080 ,可以看到客户端控制台输出为最新的值。
7、刷新Bean
前面的章节中介绍了 如何进行配置刷新,然而在实际应用中,往往不仅是只刷新一个配置的值那么简单。由于 Spring 容器中的很多 Bean 都是根据某个属性值来进行初始化的, 配置一旦更新,需要重建这个 Bean 的实例。 为了解决该问题, Spring Cloud 提供了@RefreshBean 注解。
在Spring 的容器中,有一个类型为 RefreshBean 的 Bean 。当 /refresh 端点被访问时,负 责处理刷新的 ContextRefresher 类会先去远程的配置服务器刷新配置,然后再调用RefreshBean 的 refreshAll 方法来处理理实例 。容器中使用了@RefreshBean 注解进行修饰的 Bean, 都会在缓存中进行销毁,当这些 Bean 被再次引用时,就会创建新的实例,以此达到一个“刷新”的效果。
在客户端(srl-book-server) 中测试刷新 Bean,新建配置类,请见代码清单 -5
@Configuration
public class MyConfig {
@Bean
@RefreshScope
public Person person(Environment env) {
// 读取名字创建Person实例
String name = env.getProperty("test.user.name");
// 输出person名字
System.out.println("初始化 person bean:" + name);
//创建一个Person
Person person = new Person();
person.setName(name);
return person;
}
public static class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
在配置类中会创建一个 Person 的 Bean, Bean 会读取 test.user.name 属性来创建 Person实例,该属性保存在 SYN 的配置文件中。修改一下控制器,请见代码清单 9-6。
/**
* 测试刷新Bean
*/
@Autowired
private Person person;
@RequestMapping("/person")
public String getPerson() {
System.out.println("输出person实例的名称:" + person.getName());
return person.getName();
}
往控制器中注入 Person ,访问 /person 地址后,会输出当前容器中的 Person 以及名字。 当前 SVN中 first-test.properties的 test.user.name 属性值为 Songrongliang,依次启动服务器、客户端,访问 http: //localhost: 8080/person ,可以看到客户端的控制台输出如下:
初始化 person bean:Songrongliang
修改 SVN 中的配置文件并提交,然后向 http://localhost: 8080/refresh 端点发送 POST请求(运行 RefreshClient ),最后再次访问 http ://localhost: 8080/person ,可以看到客户端控制台输出如下:
初始化 person bean:xieyinan
输出person实例的名称:xieyinan
根据输出可知,属性值己经被刷新,使用该属性值创建的 Person 实例己经被重新创建。