Nacos除了提供了注册中心的功能,同样也提供了配置中心的功能,用于管理一些叫常改动的配置
当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。

Nacos一方面可以将配置集中管理,另一方可以在配置变更时,及时通知微服务,实现配置的热更新。
下面我们就来使用Nacos配置一下服务的(部分)配置文件
这里说部分还是因为在上面说的我们不会把所有的信息都配置到服务中, 只是把一些常修改的配置
单独提出来项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。
1. 在Nacos里添加配置文件
步骤1 添加配置:
在nacos主界面的配置列表中点击加号

然后在弹出的表单中,填写配置信息:
ID配置规则: 服务名-配置类型.后缀
分组默认即可

步骤2 从微服务拉取配置
上面我们只是在Nacos中创建了配置文件,但是在真实的微服务项目中还没有使用,此时需要在服务中拉取对应的配置
微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。
但如果尚未读取application.yml,又如何得知nacos地址呢?
此时要做的就是将我们的配置和服务中的配置一并生效
因此spring引入了一种新的配置文件:bootstrap.yaml文件,会在application.yml之前被读取,流程如下:

此时就可以读取到我们在Nacos中配置的文件
- 引入nacos-config依赖
 
在user-service服务中,引入nacos-config的客户端依赖:
<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <!-- 像这种通用的版本配置我们一般交给父工程管理,这里我先加上 -->
    <version>2.2.6.RELEASE</version>  
</dependency>
 
- 添加bootstrap.yaml
 
然后,在user-service的resources目录添加一个bootstrap.yaml文件,内容如下:
spring:
  application:
    name: userservice # 服务名称
  profiles:
    active: dev #开发环境,这里是dev 
  cloud:
    nacos:
      server-addr: 127.0.0.1:80 # Nacos地址 因为我配置了Nacos集群环境这里我就写我的Nginx地址
      config:
        file-extension: yaml # 文件后缀名
 
这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件id,来读取配置。
本例中,就是去读取user-service-dev.yaml:

此时就可以读取在Nacos配置中心配置的配置项
- 读取nacos配置
 
在user-service中的UserController中添加业务逻辑,读取pattern.dateformat配置:
使用@Value注解,再使用$表达式,指定对应的配置,即可注入获取到具体的值,后面就可以使用读取到的内容了
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @Value("${pattern.dateformat}")   // 读取配置
    private String dateformat;
    
    @GetMapping("/now")
    public String now(){
         return new SimpleDateFormat(dateformat).format(new Date())
    }
    // ...略
}
 
在页面访问,可以看到效果:

2. 配置热更新
所谓的热更新就是在修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新。
要实现配置热更新,可以使用两种方式:
方式一 通过@Value注解+ @RefreshScope注解
注解看刚才的代码
@Slf4j
@RestController
@RefreshScope 
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @Value("${pattern.dateformat}")   // 读取配置
    private String dateformat;
    
    @GetMapping("/now")
    public String now(){
         return new SimpleDateFormat(dateformat).format(new Date())
    }
    // ...略
}
 
此时当Nacos配置文件中的pattern.dateformat发生对应的@Value读取到的数据也会更改
方式二 使用@ConfigurationProperties
这个注解可能在之前用过,作用时批量的读取配置信息,而在这里@ConfigurationProperties注解天然支持配置文件的热更新
在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 dateformat;
}
 
在UserController中使用这个类代替@Value:
@Slf4j
@RestController
// @RefreshScope 
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    // 注入配置类
    @Autowired
    private PatternProperties patternProperties;
    @GetMapping("/now")
    public String now(){
        return new SimpleDateFormat(patternProperties.getDateformat()).format(new Date())
    }
}
 
这两种方式都可以实现当Nacos中的配置文件更新时,对应的读取配置的地方也做相应的更新
那么什么时候使用第一种什么时候使用第二种热更新方式呢?
对于第一种我们会发现很方便, 直接在对相应的成员变量和类上添加对应的注解即可.但是不好的地方是如果有多个配置需要读取时, 我们就需要写一大~~~~堆,此时在这种方式就很麻烦,而此时使用第二种方式就很好, 自动的一次性赋值
总结: 当少于两个配置的时候使用第一种方式, 当大于两个使用第二种方式进行配置的热更新
3. 配置共享
其实微服务启动时,会去nacos读取多个配置文件,例如:
-  
[spring.application.name]-[spring.profiles.active].yaml,例如:user-service-dev.yaml -  
[spring.application.name].yaml,例如:user-service.yaml 
而[spring.application.name].yaml不包含环境,因此可以被多个环境共享。
那下面我们我们就对其做一个测试,
-  
在Nacos中添加一个共享的配置
我们在nacos中添加一个user-service.yaml文件:
 

-  
在user-service中读取共享配置
这里使用热更新的方式一
 
@Slf4j
@RestController
@RefreshScope
@RequestMapping("/user")
public class UserController {    
    
    // 公共配置
	@Value("${commons.message}")
    private String message;
    
	// 独有的配置
    @Value("${pattern.format}")
    private String pattern;
    @GetMapping("/show")
    public String showMessage() {
        return new SimpleDateFormat(pattern).format(new Date()) + message;
    }
}
 
此时访问可以看到已经读取到了公共的配置

此时创建一个user-service示例,作为test实例,修改其配置文件
 
然后右键当前拷贝后的配置,编辑当前的配置

操作如下: 修改端口


可以看到这里有一个Active profiles的配置, 因为我们较常修改这些配置,所以idea就给提出来了,他对应的就是我们在配置文件中配置的配置项,来指定当前的实例是dev还是test

此时就会多一个为test版的服务实例,我们在Nacos创建对应的配置文件

这里日期的格式化故意和dev环境区别
此时运行项目访问两个user-service服务查看结果

共享信息都读取到了,测试成功
配置文件优先级问题
我们回顾一下,我们的配置可以在本地配置,可以在共享配置中配置也可以在nacos对应配置文件中配置,那么谁的优先级更高呢?即当同时又一个配置时谁生效呢? 优先级如下:



















