1.引言
上一节我们借助于Nacos实现注册中心,完美替换了Eureka在项目之初的功能,开始本章节之前我们一起回忆下Nacos实现注册中心的关键步骤
引入springcloud-alibaba/nacos-discovery依赖
去除原eureka依赖、去除配置文件中eureka注册信息
新增nacos注册信息:spring.cloud.nacos.server-addr:localhost:8848
重启项目并验证
在此基础之上我们验证了Nacos的负载均衡策略、权重控制、环境隔离等信息,希望大家还能有点印象。
2.为什么需要配置中心
试想最初的单体应用到如今的微服务部署(服务可能上百个),配置文件从修改到重启完成,服务中断可以按分钟计。以笔者负责应用为例,当数十数百个应用都需要修改配置,每个都重启部署的时候,服务中断将不再是可估算的现象。
因此我们需要一个类似注册中心的中间件,将配置中心从应用中解耦,应用不再是完全读取本地配置(部分不会频繁热更新的参数仍应用自身维护),而是直接拉取配置中心的信息作为应用参数,后续执行自己的业务流程。
下图为Nacos实现原理图:
但是引入配置中心的同时,我们不免思考一些Nacos已经遇到过、并成功解决的问题:
配置中心挂了怎么办?
谁负责将配置变更同步给应用?pull?push?
配置中心本身多节点部署,自身数据不同步又该如何解决呢?
Nacos是如何解决这些问题的,读者们可以参见上一节:Nacos白皮书或等笔者后续给出分析,基于上述背景,我们本章节将借助Nacos带领大家实现一个配置中心。
3.Nacos实现配置中心
3.1 新增配置信息
Nacos实现配置中心较为简单,首先在服务端新增一个配置信息(profile指项目运行环节:dev/test/pro)
注意:此处笔者新增在public空间下,如有部分读者是dev添加,则对应需要追加namespace(参见上节)
3.2 微服务拉取配置信息
配置完成之后,下一步就是在应用中拉取到刚才的配置信息。回顾我们原来的应用启动过程,应用启动时会读取本地配置文件application.yml,nacos也不例外他会将nacos配置信息同application.yml中的信息合并输出。那么问题来了:如果应用不能先读取到nacos配置信息(nacos地址-->配置信息)又怎么合并到一起呢?因此Spring引入一个新的配置文件:bootstarp.yaml文件,其读取顺序要优先于application.yml文件,如下:
1.引入nacos-config依赖
在user-service中新增nacos-config依赖
2.新增bootstrap.yaml文件
在user-service中新增配置文件:bootstrap.yaml,内容如下:
此时应用就会使用以下规则作为文件的DataId匹配对应的配置文件:{spring.application.name}-${spring.procile.active}.${spring.cloud.nacos.config.file-extension}
以本例为准读取的即为:userservice-dev.yaml
3.应用读取nacos配置
对于nacos的配置其使用也做到了开箱即用,只需借助@Value注解即可,我们做如下添加
访问应用发现即生效
4.Nacos配置热更新
如果只是做到了配置中心,显然对于Nacos的配置中心的能力是有所低估的,nacos可以做到毫秒级配置热更新,其实现也有多种方式。
1.@RefreshScope
在@Value注入变量所在类上增加@RefreshScope即可,代码如下:
修改后我们重启应用并发完一次,发现访问效果没变,此时我们修改配置文件如下,并点击发布:
注意:此时我们做了两件事情:①修改配置 ②发布配置,但是没有重启应用
再次访问,发现配置已及时生效,如下所示,感兴趣的也可以做更多格式的尝试,会发现都是及时生效
实际当用户修改配置文件时,nacos会通知客户端此时配置更新,日志如下:
如果有读者对@RefreshScope的热更新感兴趣,可移步至:@RefreshScope热更新原理
2.@ConfigurationProperties注解替代@Value
我们在user-service工程中新增一个配置类,用于读取此例中配置信息,代码如下:
配置类文件
Java
运行代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package cn.itcast.user.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
- 配置读取类
* - @author
@date 2023-01-01 21:53
*/
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {private String dateformat;
}