非Spring项目如何集成nacos使用
1.nacos是什么
根据nacos官方的介绍,nacos为Dynamic Naming and Configuration Service的首字母简称,是一个一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
笔者个人对nacos的理解则是,spring cloud Alibaba解决方案下配置中心所使用的组件,主要是用来做服务注册与发现,配置管理。
2.nacos怎么用
nacos官方文档给出了nacos生态下与一些主流框架的集成方案。
但从非主流框架下的JavaWeb应用角度来说,在实际开发情况下,亦需要多环境开发测试及上线,就会出现多套代码不同配置文件的情况。可能该情况现有使用较多的解决方案是代码版本管理,但这会带来另外的问题。
- 首当其冲的便是效率问题,更改配置问题,上传代码库,应用重新部署,有几个环境就需要操作几次。当然,该问题也可以采用另一篇文章中提到的Jenkins自动触发的方式来进行优化。
- 其二则是不能对程序配置文件进行统一管理,各环境,各应用配置文件分散在各个代码包中,不易于检索,排查,更新。
因此在传统JavaWeb应用中使用配置中心也是有益无弊的举措。但相较于主流开发框架即拿即用的部署及集成来讲,传统web应用的集成存在一定的难度,因为并不存在服务注册与发现的过程,并不能直接拿到配置中心的相关配置进行使用。
但是在这里,笔者提出两个自己的解决方案,经实测都生效且有较好的效果。
3.非Spring项目集成nacos使用
3.1 方案一:调用官方提供接口拿到配置值
nacos官方提供包含但不限于以下的几个接口:
- 获取某个dataId的配置内容
http://${ip}:${port}/nacos/v1/cs/configs?dataId=${dataId}&group=${group}&tenant=${tenant}
- 获取多个dataId的配置内容
http://${ip}:${port}/nacos/v1/cs/configs?dataId=${dataId1}&group=${group}&tenant=${tenant}&dataId=${dataId2}&group=${group}&tenant=${tenant}
- 下载整个group的配置内容
http://${ip}:${port}/nacos/v1/cs/configs?search=accurate&dataId=&group=${group}&tenant=${tenant}
- 下载某个namespace下所有的配置
http://${ip}:${port}/nacos/v1/cs/configs?search=accurate&dataId=&group=&tenant=${tenant}
- 获取某个dataId的配置内容
http://${ip}:${port}/nacos/v1/cs/configs?dataId=${dataId}&group=${group}&tenant=${tenant}
其中,dataId和group参数必须传递,tenant参数可选。
基本思路就是,通过上述接口拿到配置中心当前应用的配置项,再通过脚本语言进行解析,存放到相应的文件夹下面。最后将该脚本放到tomcat的启动脚本catalina.sh中,让程序在启动时就去获取,解析,存储。
笔者在nacos的配置如下
并且已将应用中所有配置文件删除
可以看到在目标目录Config和CnfgSpace下都已无配置文件。
shell脚本如下:
#!/bin/bash
# set -e
# set -x
# TODO: 替换为 Nacos Server 的 IP 地址和端口号
ip="127.0.0.1"
port="8848"
# TODO: 替换为要获取的配置所在的分组和租户名(如果没有可以不填)
group="local"
# TODO: 替换为每次请求获取的数据条数
pageSize="20"
pageNo="1"
# TODO: 替换为需要获取的配置列表的dataId前缀(如果不需要限定前缀,设为 "")
# prefix=""
baseURL="http://${ip}:${port}/nacos/v1/cs/configs?search=accurate&dataId=${prefix}&group=${group}&pageSize=${pageSize}&pageNo=${pageNo}"
# 发送 HTTP totalCount 和 pagesAvailable(总页数)
totalCount=$(curl -s -X GET ${baseURL} | jq -r '.totalCount')
pageNumber=$(curl -s -X GET ${baseURL} | jq -r '.pageNumber')
pagesAvailable=$(curl -s -X GET ${baseURL} | jq -r '.pagesAvailable')
echo "总共有 $totalCount 个配置,共 $pagesAvailable 页"
# 遍历每一页,获取其中的配置并存储到对应的文件夹中
for ((pageNo=1; pageNo<=pagesAvailable; pageNo++)); do
echo "开始获取第 $pageNo 页配置..."
# 发送 HTTP 请求获取当前页的配置
pageItems=$(curl -s -H "Content-Type:application/json" -X GET ${baseURL} | jq -r '.pageItems' )
# 遍历当前页的每一个配置,将其内容写入对应的文件
# 定义变量,指定文件夹名称
folderA="/Users/liuzhengdong/project/hrssc/project-svn/CNPC-SSC/ssf-application/ssfServerDev/WEB-INF/CnfgSpace"
folderB="/Users/liuzhengdong/project/hrssc/project-svn/CNPC-SSC/ssf-application/ssfServerDev/WEB-INF/classes/Config"
# 解析json数组,遍历每一个item对象
for item in $( printf "%s\n" "${pageItems}" | tr -d ' ' | jq -r -c '.[]' ); do
# 's/ /%20/g; s/\([^\\]\)\\/\1 /g'
# for item in $( printf "%s\n" "${pageItems}" | tr ' ' '%20' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\\\([^n]\)/\1/g' -e 's/\\"/"/g' | jq -r -c '.[]' ); do
# for item in $( printf "%s\n" "${pageItems}" | sed -i 's/:\s\+"/: "/g' | jq -r -c '.[]' ); do
# 从当前item中提取dataId、content、fileType
dataId=$(printf "%s\n" $item | jq -r '.dataId')
content=$(printf "%s\n" $item | jq -r '.content')
fileType=$(printf "%s\n" $item | jq -r '.type')
# 判断dataId是否为"DBConfig.xml"
if [ "${dataId}" = "DBConfig.xml" ]; then
# 写入文件夹A中的DBConfig.xml文件
folder=${folderA}
fileName=${dataId}
else
# 写入文件夹B中的dataId文件
folder=${folderB}
fileName=${dataId}
fi
# 判断文件是否存在,不存在则创建文件
if [ ! -f "${folder}/$fileName" ]; then
mkdir -p $folder
touch ${folder}/$fileName
fi
# 写入内容到文件中
printf "%s\n" "$content" > "$folder/$fileName"
if [ "${dataId}" = "DBConfig.xml" ]; then
file_path="${folderA}/DBConfig.xml"
# 替换第一行
sed -i '.backup' '1s/.*/<?xml version="1.0" encoding="UTF-8"?>/' "${file_path}"
sed -i '.backup' '/name/s/\(name\)/ \1/' "${file_path}"
# 使用xmllint对文件进行格式化
xmllint --format "${file_path}" > "${file_path}.tmp"
# # 将格式化后的结果替换原文件
mv "${file_path}.tmp" "${file_path}"
echo "xml文档的处理已完成"
fi
done
done
echo "完成获取配置,配置文件已同步更新。"
由于返回全部为json格式,需要对DBConfig.xml文件单独处理一下。
将该脚本放在catalina.sh文件中
控制台输出相关日志
同样地,相关配置文件也已获取到
应用也成功部署并且登录成功。
3.2 方案二:巧用nacos的下载功能
方案一虽成功达到目的,但仍存缺陷。
比如拿到的json文件的解析,在xml的解析上,jq并不能精准地解析出来。反而是需要对xml进行单独的处理。在笔者使用nacos的过程中发现nacos提供下载按钮,且下载内容为完整的zip压缩包,因此通过对下载链接的解析及调试,得到如下可行且无需token的下载链接:
http://127.0.0.1:8848/nacos/v1/cs/configs?export=true&tenant=&group=local&appName=&dataId=&ids=&username=nacos
username非必需,只需要将group带在链接中即可。
因此,只需要通过该链接,将相关内容下载到目标文件夹,再移动到目标文件夹,再部署应用即可。
同样地,先删除相关配置内容:
再将如下的脚本,放到catalina.sh文件中,启动时执行。
#/bin/bash
folderA="/Users/liuzhengdong/project/hrssc/project-svn/CNPC-SSC/ssf-application/ssfServerDev/WEB-INF/CnfgSpace"
folderB="/Users/liuzhengdong/project/hrssc/project-svn/CNPC-SSC/ssf-application/ssfServerDev/WEB-INF/classes/Config"
group="local"
ip="127.0.0.1"
port="8848"
# 下载zip包到本地
curl -s -o ${folderB}/data.zip "http://${ip}:${port}/nacos/v1/cs/configs?export=true&tenant=&group=${group}&appName=&dataId=&ids=&username=nacos" --output data.zip
# wget http://127.0.0.1:8848/nacos/v1/cs/configs?export=true&tenant=&group=local&appName=&dataId=&ids=&username=nacos -O ./data.zip
cd ${folderB}
# 解压zip包
unzip -o -q data.zip
# 处理local下的DBConfig.xml
if [ -f local/DBConfig.xml ]; then
# 将DBConfig.xml移动到A文件夹下
mv -f local/DBConfig.xml ${folderA}/
else
# 如果不存在,则提示错误信息
echo "未获取到数据库配置DBConfig.xml文件"
fi
# # 处理其他文件
mv -f "${folderB}/${group}/"* "${folderB}/"
rm -rf local
rm -f data.zip
echo "系统配置获取已完成"
done
启动应用
配置获取成功且启动成功,该报错恰好说明执行的是刚才圈的V2文件。
4.非Spring项目与nacos
其实从实际意义上来说,非Spring应用上nacos有点强行集成的意思。因为nacos本来就是SpringCloud Alibaba解决方案中注册中心和配置中心的最优选,非该框架下的应用何必强行找不痛快呢?
但同样是从实际意义来看,配置中心的使用,却又能在实在意义上使系统开发更规范,配置内容使用更整洁。举个简单的例子,某业务服务范围,很明显这是一个变量,但是系统各个地方都会用到,写死明显不合适,写在代码中互相引用代码耦合性太强,配置中心的优势在此刻即得到展现。