8、Nacos统一配置管理
当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。
然后在弹出的表单中,填写配置信息:
注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。
2.从微服务拉取配置
微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。
但如果尚未读取application.yml,又如何得知nacos地址呢?
因此spring引入了一种新的配置文件:bootstrap.yaml文件,会在application.yml之前被读取,流程如下
1)引入nacos-config依赖
<!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
2)添加bootstrap.yaml
然后,在user-service的resource下添加一个bootstrap.yaml文件,内容如下:
spring:
application:
name: user-service # 服务名称
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
discovery:
namespace: f81f5f9b-6eaf-4766-92f0-2479c9c73ebc # 服务注册在哪个命名空间ID
cluster-name: HZ # 集群名称
config:
file-extension: yaml # 文件后缀名
group: DEFAULT_GROUP # 分组
同时将 application.yml 文件中相同的内容删除,剩余内容如下
server: port: 5601 logging: level: cn.itcast: debug pattern: dateformat: MM-dd HH:mm:ss:SSS
这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
作为文件id,来读取配置。
本例中,就是去读取userservice-dev.yaml
:
3)读取nacos配置
在user-service中的UserController中添加业务逻辑,读取pattern.dateformat配置:
package cn.itcast.user.web; import cn.itcast.user.pojo.User; import cn.itcast.user.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @Slf4j @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @Value("${pattern.dateformat}") private String dateformat; @GetMapping("now") public String now(){ return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat)); } // ...略 }
重启user-service服务在页面访问,可以看到效果:
我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新。
要实现配置热更新,可以使用两种方式:
方式一
在@Value注入的变量所在类上添加注解 @RefreshScope:
方式二(推荐)
使用@ConfigurationProperties注解代替@Value注解。
在user-service服务中,添加一个类,读取patterrn.dateformat属性:
package cn.itcast.user.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dataFormat;
}
在UserController中使用这个类代替@Value:
package cn.itcast.user.web; import cn.itcast.user.config.PatternProperties; import cn.itcast.user.pojo.User; import cn.itcast.user.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @Slf4j @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @Autowired private PatternProperties patternProperties; @GetMapping("now") public String now(){ return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDataFormat())); } }
4.配置多环境共享
public命名空间下:user-service.yml
public命名空间下:user-service-sit.yml
public命名空间下:user-service-dev.yml
sit命名空间下:user-service-sit.yml
dev命名空间下:user-service-dev.yml
其实微服务启动时,会去nacos读取多个配置文件,例如:
-
[spring.application.name]-[spring.profiles.active].yaml
,例如:userservice-dev.yaml -
[spring.application.name].yaml
,例如:userservice.yaml
而[spring.application.name].yaml
不包含环境,因此可以被多个环境共享。
无论profile如何,[spring.appliction.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件
注意:bootstrap.yaml 的未配置 namespace 时,默认查询 public 命名空间中上面的两个配置文件,当配置 namespace 命名空间,则只会在当前命名空间中搜索上面的两个配置文件,故需要做多环境共享配置,需要在public空间创建配置文件,在 bootstrap.yaml 的 config 下不配置 namespace 字段
spring:
application:
name: user-service # 服务名称
profiles:
active: sit #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
discovery:
namespace: 53955767-95e1-4b5d-9ad9-4b0fa7ac8d94 # 命名空间ID,用作环境隔离,服务注册在哪个命名空间
cluster-name: HZ # 集群名称
config:
file-extension: yaml # 文件后缀名
group: DEFAULT_GROUP
# namespace: 53955767-95e1-4b5d-9ad9-4b0fa7ac8d94 # 命名空间ID,用作在哪个空间查找 user-service.yaml、user-service-sit.yaml 文件; 无该字段,默认从 public 空间查找
下面我们通过案例来测试配置共享
1)添加一个环境共享配置
2)在user-service中读取共享配置
在user-service服务中,修改PatternProperties类,读取新添加的属性:
在user-service服务中,修改UserController,添加一个方法:
这样,在不同命名空间的服务实例就都可以访问到 user-service.yaml文件中的值
5.多服务共享配置
1、在public下创建common.yaml 文件
2、在要使用该配置文件的服务中 bootstrap.yaml 增加 shared-configs 或 extension-configs
不同微服务之间可以共享配置文件,通过下面的两种方式来指定
方式一:
spring:
application:
name: user-service # 服务名称
profiles:
active: sit #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
discovery:
namespace: 53955767-95e1-4b5d-9ad9-4b0fa7ac8d94 # 命名空间ID,用作环境隔离,服务注册在哪个命名空间
cluster-name: HZ # 集群名称
config:
file-extension: yaml # 文件后缀名
group: DEFAULT_GROUP
# namespace: 53955767-95e1-4b5d-9ad9-4b0fa7ac8d94 # 命名空间ID,用作在哪个空间查找 user-service.yaml、user-service-sit.yaml 文件
shared-configs: # 多服务间共享的配置列表
- dataId: common.yaml # 本服务要读取的共享配置文件名称
方式二:
spring:
application:
name: order-service # 服务名称
profiles:
active: sit #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
discovery:
namespace: 53955767-95e1-4b5d-9ad9-4b0fa7ac8d94 # 命名空间ID,用作环境隔离,服务注册在哪个命名空间
cluster-name: HZ # 集群名称
ephemeral: false # 设置为非临时实例
config:
file-extension: yaml # 文件后缀名
group: DEFAULT_GROUP
# namespace: 53955767-95e1-4b5d-9ad9-4b0fa7ac8d94 # 命名空间ID,用作在哪个空间查找 user-service.yaml、user-service-sit.yaml 文件
extension-configs: # 多服务间共享的配置列表
- dataId: common.yaml # 本服务要读取的共享配置文件名称
添加相应的配置读取文件,加注解 @ConfigurationProperties
package cn.itcast.order.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @Data @ConfigurationProperties(prefix = "common") public class CommonProperties { private String name; }
在Controller 类中使用
package cn.itcast.order.web; import cn.itcast.order.config.CommonProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("order") public class OrderController { @Autowired private CommonProperties commonProperties; @GetMapping("common") public String common() { return commonProperties.getName(); } }
重启服务,浏览器访问 http://ip:port/order/common
可以看到能够返回了 common.yaml 文件中配置的 common.name 字段值