在Nacos中,可以做配置给服务做配置管理,在现实中,我们需要更新某个在运行中的服务的配置时,如果将服务停下来修改了配置在重启,对于在生产环境中的服务可能影响比较大,对此,Nacos对配置进行管理,还可以进行热更新,实时的刷新到运行的服务中。

案例

user-service服务中配置了日期时间的格式为yyyy-MM-dd HH:mm:ss,想不修改本地的配置文件的情况下,修改日期时间的格式为yyyy年MM月dd日 HH:mm:ss,在Nacos中如何实现,就要涉及到它的统一配置管理。

统一配置管理

image-1655300885928

通过以上的图片可以看出,在服务启动的时候,会同时去将本地的application.yml配置和Nacos中的配置文件都读取出来,然后再进行后续的操作。但是,服务是如何知道Nacos的信息以及Nacos里面的配置信息的呢?而且我们对于Nacos的配置还在本地的application.yml文件中,难道是先加载本地的配置文件,先读取到Nacos的信息,再去Nacos中读取配置信息吗?
其实不是的,我们都知道,在spring的配置文件中,还有一个配置文件比application.yml的级别要高,那就是bootstrap.yml,它会比application.yml先被读取到,所以,对于以上的问题,就可以解决了,我么将Nacos的信息配置到bootstrap.yml文件中,就可以先读取到Nacos的信息,在根据这些信息去读取Nacos中的配置信息,然后再将其和本地的合并起来即可。

Nacos中添加配置

image-1655301419628


image-1655302110344


image-1655301465296


添加依赖

在需要进行配置管理的服务的pom中添加Nacos的配置依赖支持,这里我们为user-service添加。

<!-- nacos配置管理依赖 -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

在userservice中的resource目录添加一个bootstrap.yml文件,这个文件是引导文件,优先级高于application.yml

bootstrap.yml

spring:
  application:
    name: userservice
  profiles:
    active: dev
  cloud:
    nacos:
      server-addr: localhost:8848
      config:
        file-extension: yaml
        namespace:

application.yml,在本地中,我们没有多配制其他的

server:
  port: 8081

可以发现,bootstrap.yml中的name和active,以及file-extension,刚好可以组成我们在Nacos中的配置文件的名称userservice-dev.yaml

测试

我们在Controller中写一个可以获取打印配置的接口:

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Value("${pattern.dateformat}")
    private String dateformat;

    @GetMapping("/getdate")
    public String getdate(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }
}

启动user-service服务,请求接口结果,可见配置已经生效

image-1655302174608

热更新

在上述中,我们实现了Nacos的配置管理,并且已经生效,但是,现在尝试在Nacos中修改配置:

image-1655302412991

再去访问之前的接口,发现并没有生效,那该如何实现配置的热更新呢?
有两种方式可以实现:

方式一:@RefreshScope

在我们使用到了Nacos的代码中的类上,配置@RefreshScope注解,即可实现配置的热更新:

@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {

    @Autowired
    private UserService userService;

    @Value("${pattern.dateformat}")
    private String dateformat;

    @GetMapping("/getdate")
    public String getdate(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }
}

方式二:定义配置类

可以将需要在Nacos中配置的属性,定义成一个类,就以上的案例,我们可以这样定义:

@Data
@Component
@ConfigurationProperties(prefix = "pattern")//使用pattern前缀,可以将前缀为pattern的配置加载到类中,并自动按命名匹配
public class PatternProperties {
    private String dateformat;
}

那此时的接口代码就应该如下写了,需要将我们定义的配置类,注入到需要使用的地方:

@RestController
@RequestMapping("/user")
//@RefreshScope//此时我们就不需要这个注解了
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    PatternProperties properties;

    @GetMapping("/getdate")
    public String getdate(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));
    }
}

这样的方式,同样可以实现配置的热更新。

相同微服务的多环境配置共享

其实,微服务启动时会从nacos读取多个配置文件:
[spring.application.name]-[spring.profiles.active].yaml,例如:userservice-dev.yaml
[spring.application.name].yaml,例如:userservice.yaml
无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件。
在Nacos中,在此添加一个配置文件userservice.yml

image-1655303206601


image-1655303162795
然后我们在接口中再定义一个访问共享属性的接口:

PatternProperties.java

@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dateformat;
    private String enSharedValue;
}
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    PatternProperties properties;

    @GetMapping("/getdate")
    public String getdate(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));
    }

    @GetMapping("/properties")
    public PatternProperties getenshard(){
        return properties;
    }
}

然后,在我们启动的时候,多启动一个环境为test的实例:

image-1655303860754

访问:
image-1655304795522


image-1655304808079


为什么8082端口的dateformat是空的?因为我们在Nacos中根本没有配置userservice-test.yml的信息,所以获取不到,只能获取到共享的配置userservice.yml

相同微服务的多种配置的优先级

image-1655305006577

不同微服务的环境共享

首先创建一个common.yaml代表不同微服务的共享配置文件

image-1655305791735

同时,在每一个微服务下面创建自己的bootstrap.yml配置文件,并设置共享的配置文件

image-1655305954102

然后再自己的接口中定义访问共享属性的接口:

image-1655306311869

测试,可以看到,两个不同的微服务都加载了common.yaml共享配置文件

image-1655306410740

除此配置方式之外,还有一种非常类似的方式,就是将bootstrap.yml中的shared-configs换成extension-configs即可:

image-1655307442614

不同微服务的多环境优先级

image-1655307490536