项目实践-SpringBoot实时获取Nacos配置文件内容(.yaml文件)
**书山有路勤为径,学海无涯苦作舟**
记录程序员生活点点滴滴,希望记录的内容能帮助到努力爬山的各位伙伴!
标签:Nacos/yaml文件
前言
- 业务场景:分布式业务系统中各组件属性在Nacos配置列表中config.yaml文件中进行灵活配置,系统通过接口从config.yaml文件中获取各组件属性再进行页面渲染。
- 功能要求:
- config.yaml中各组件属性可以灵活修改/增删,接口都可以获取最新的配置内容,并且不需要重启服务。
- 接口返回前端的内容不能改变config.yaml内容的数据格式(yaml文件格式)。
一、SpringBoot集成Nacos
1.引入Maven依赖
<!--nacos依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.4.1</version>
</dependency>
在实现方式中会涉及对yaml文件的处理,因此需要引入yaml相关jar包
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
</dependency>
2.Nacos基本配置
server:
port: 18010
spring:
main:
allow-bean-definition-overriding: true
application:
name: project-proxy
server:
ip: 127.0.0.1
cloud:
nacos:
common-file: common-config.yaml
common-file-group: prod
discovery:
server-addr: ${spring.server.ip}:8848
group: prod
config:
server-addr: ${spring.server.ip}:8848
group: prod
prefix: ${spring.application.name}
file-extension: yaml
备注:
5. 在我的项目中Nacos的基本配置信息放在bootstrap.yml文件中
6. common-file: common-config.yaml是实时读取目标文件Data_id,在Nacos中提前已经配置完成
7. common-file-group: prod是目标文件的Group
二、实现Nacos中yaml文件读取
整体思路
- 利用配置文件的DATA_ID和GROUP,通过Nacos开放接口获取yaml文件内容
- 将获取的yaml文件内容写入到固定路径下的.yaml文件中去
- 读取yaml文件内容并处理封装提供给前端
1.具体实现类
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author Miracle
* @title: WebConfigController
* @projectName proxy
* @description: 【config-api】
* @date 2021/6/215:07
*/
@RestController
@RefreshScope
@RequestMapping("/config")
public class WebConfigController {
/**
* DATA_ID
*/
@Value("${spring.cloud.nacos.common-file}")
private String DataId ;
/**
* GROUP
*/
@Value("${spring.cloud.nacos.common-file-group}")
private String group ;
/**
* 存储配置信息文件路径
*/
final String FilePath = WebConfigController.class.getClassLoader().getResource("webconfig.yml").getPath();
/**
* 默认nacos地址
*/
@Value("${spring.cloud.nacos.config.server-addr}")
private String DEFAULT_SERVER;
/**
* 获取配置文件内容config-api
* @param ipAddr
* @return
* @throws NacosException
* @throws InterruptedException
*/
@RequestMapping(value = "/configs", method = RequestMethod.GET)
public Map<String,Object> getConfig(@RequestParam Map<String, Object> params) throws NacosException, InterruptedException {
Map<String,Object> map = new HashMap<>();
Map<String,Object> resultMap = new HashMap<>();
String path = FilePath;
// 访问nacos
ConfigService configService = NacosFactory.createConfigService(DEFAULT_SERVER);
// 通过DataId和Group获取配置文件内容
String contentInfo = configService.getConfig(DataId,group,1000L);
// 将配置内容放置到固定的文件中去
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
try
{
// 本地调试访问形式
File distFile = new File(path);
if (!distFile.getParentFile().exists()) distFile.getParentFile().mkdirs();
bufferedReader = new BufferedReader(new StringReader(contentInfo));
bufferedWriter = new BufferedWriter(new FileWriter(distFile));
char buf[] = new char[1024]; //字符缓冲区
int len;
while ((len = bufferedReader.read(buf)) != -1) {
bufferedWriter.write(buf, 0, len);
}
bufferedWriter.flush();
bufferedReader.close();
bufferedWriter.close();
// 重新读取放入配置内容的config文件
Yaml yaml = new Yaml();
InputStream yamlFile = new FileInputStream(path);
// 特殊说明 本地window环境设置编码utf-8,服务器环境设置编码GB2312
InputStreamReader isr = new InputStreamReader(yamlFile,"GB2312");
BufferedReader reader = new BufferedReader(isr);
if(yamlFile != null){
map = yaml.load(reader);
}
// map中即为config.yaml文件内容,按照yaml文件格式封装成json格式
// 实际业务处理逻辑
......
}catch (Exception e){
e.printStackTrace();
}
return resultMap;
}
}
2.实现过程中遇到的“坑”
- 文件路径:博主的项目部署环境是Windows环境,在发布后按照类加载器生成的文件路径在实际生产环境中无法读取。开发环境是在项目Resource目录下生成临时webconfig.yaml文件,在生产环境则涉及到读取jar包外文件路径错误的问题,建议大家可以按照实际的环境定义好临时yaml文件路径或者程序中对获取的文件路径进行处理。
- 汉字编码:博主的目标yaml文件中存在"#注释",或者value值为汉字的配置信息,导致在读取临时yaml文件是无法序列化的问题
// 特殊说明 本地window环境设置编码utf-8,服务器环境设置编码GB2312
InputStreamReader isr = new InputStreamReader(yamlFile,"GB2312"); BufferedReader reader = new BufferedReader(isr);
通过此方法来解决汉字无法序列化的问题。
总结
*登山路上的慕码人,理解不透的地方还请各位指点!*
*欢迎大家多多指正交流!*