在上文《搭建微服务-服务注册与发现(Nacos)和远程调用(openfeign)》的基础上进行
1、创建命名空间namespace
在Nacos上创建命名空间
命名空间---新建
命名空间Id:尽量手动填写,自定义生成的Id不好记,集成项目需要
命名空间名:自定义
描述:自定义
2、 创建配置文件
配置管理---配置列表---选择自定义的命名空间---新建配置文件
Data ID:
文件名完整格式,在nacos官网可以看到:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
${prefix}-${spring.profiles.active}.${file-extension}
Group:可以自定义,默认DEFAULT_GROUP
配置格式:根据自己项目选择相应的格式,此处选择YAML
配置内容:自定义,此处暂时配置nacos连接信息用于服务注册与发现spring: cloud: nacos: discovery: server-addr: 192.168.2.102:8848 # nacos-server的地址 username: nacos # nacos-server用户名 password: nacos # nacos-server密码 namespace: shiory # 命名空间ID group: DEFAULT_GROUP # 组
3、 整合到SpringCloud项目
以下都是在公共模块:cloud-common中进行
1、添加依赖
<!--Nacos配置中心场景依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
2、修改配置文件application.yml
修改application.yml为bootstrap.yml。可以看到图标变成云图标
解释:在Spring Cloud应用中,会先创建一个BootstrapContext引导上下文,比SpringBoot创建ApplicationContex(应用上下文)更早初始化。BootstrapContext 新增了一个bootstrap.yaml配置文件,保证和ApplicationContext的application.yaml配置文件的隔离。
在 bootstrap.yml 中添加Nacos配置信息
spring: cloud: nacos: config: server-addr: 192.168.2.102:8848 # nacos-server的地址 username: nacos # nacos-server用户 password: nacos # nacos-server密码 namespace: shiory # 命名空间ID group: DEFAULT_GROUP # 组 # 文件名是通过公式来拼接的: ${prefix}-${spring.profiles.active}.${file-extension} prefix: shiory-cloud # 配置文件名前缀${prefix} file-extension: yml # 配置文件名扩展${file-extension} profiles: active: dev # 配置文件名扩展${spring.profiles.active}
4、Nacos动态刷新
动态刷新:不停机动态修改配置,立即生效。Nacos默认自动刷新。查看源码可知,NacosConfigProperties中refreshEnabled属性默认为true
1、常用获取动态刷新值的三种情况
扩展:springboot 读取 yml 配置的几种方式 - mysgk - 博客园
1、@ConfigurationProperties 注解获取
在步骤2新创建的配置文件中,加入测试属性,如下
在cloud-demo3模块中创建测试刷新配置类TestNacosRefreshConfig,加上@ConfigurationProperties注解 ,同时加上@Component注解
注意事项:
a、@ConfigurationProperties注解加上后上方会飘红,虽然不影响功能,但是出于强迫症,所以在cloud-common模块的pom文件中,加上了去除飘红的注解的依赖,此外还加了一个lombok注解。
<!--@ConfigurationProperties注解飘红去除--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> </dependency>
b、@ConfigurationProperties注解中prefix属性(统一前缀)里面不能用驼峰写法,全部小写,不然会报错:Prefix must be in canonical form
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * ===================================================== * @Component + @ConfigurationProperties 测试Nacos自动刷新 * @author 汐小旅Shiory * @date 2021/12/9 21:53 * ===================================================== */ @Data @Component @ConfigurationProperties(prefix = "config.refresh.test") public class TestNacosRefreshConfig { private String name; private Integer age; private String sex; }
注入使用:在Controller中注入该配置类,然后返回。当在Nacos配置中心修改内容后,不需要重启服务,发现配置更新了
2、@RefreshScope注解 + @Value注解获取
在步骤2新创建的配置文件中,加入测试属性,如下
通过@Value注解注入使用,同时在类上加上@RefreshScope注解,当在Nacos配置中心修改内容后,不需要重启服务,发现配置更新了
3、注入Environment,通过getProperty("属性")方法获取
在步骤2新创建的配置文件中,加入测试属性,如下
注入Environment使用,通过getProperty方法获取,当在Nacos配置中心修改内容后,不需要重启服务,发现配置更新了
注意:Environment是spring中的(org.springframework.core.env.Environment)
4、最终测试Controller(cloud-demo3)
import com.shiory.demo3.config.TestNacosRefreshConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * ===================================================== * * @author 汐小旅Shiory * @date 2021/12/9 22:08 * ===================================================== */ @RefreshScope // 仅供@Value注解测试使用,其他测试删除此注解 @RestController @RequestMapping("/testNacosRefresh") public class TestNacosRefreshController { //========================测试3================================== @Autowired private Environment environment; @GetMapping("/envTest") public String test2(){ String result = "自定义测试Nacos动态刷新,envTestRefresh = " + environment.getProperty("envTestRefresh"); return result; } //========================测试2================================== @Value("${valueTest}") private String valueTest; @GetMapping("/valueTest") public String test3(){ String result = "自定义测试Nacos动态刷新,valueTest = " + valueTest; return result; } //========================测试1================================== @Autowired private TestNacosRefreshConfig testNacosRefreshConfig; @GetMapping("/config") public TestNacosRefreshConfig test1(){ return testNacosRefreshConfig; } }
2、环境变化事件监听器获取刷新值
可参考:芋道 Spring Cloud Alibaba 配置中心 Nacos 入门 | 芋道源码 —— 纯源码解析博客
实现对配置的监听,执行自定义的逻辑。只要Nacos中的配置文件有变化,此处就会监听到。当然,自定义的环境变化监听器必须放在能被扫描的包下。
例如说,当数据库连接的配置发生变更时,我们需要通过监听该配置的变更,重新初始化应用中的数据库连接,从而访问到新的数据库地址。在 Spring Cloud 中,在 Environment 的属性配置发生变化时,会发布 EnvironmentChangeEvent 事件。这样,我们只需要实现EnvironmentChangeEvent 事件的监听器,就可以进行自定义的逻辑处理。
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; /** * ===================================================== * 自定义环境变化监听器 * @author 汐小旅Shiory * @date 2021/12/8 23:25 * ===================================================== */ @Slf4j @Component public class EnvironmentChangeListener implements ApplicationListener<EnvironmentChangeEvent>, EnvironmentAware { @Autowired private Environment environment; @Override public void onApplicationEvent(EnvironmentChangeEvent event) { if (event == null) { return; } for (String key : event.getKeys()) { // 在此处可以处理自己的逻辑 log.info("[onApplicationEvent][key({}) 最新 value 为 {}]", key, environment.getProperty(key)); } } @Override public void setEnvironment(Environment environment) { this.environment = environment; } }