目的
在微服务中,knife4jAggregation通常需要为每个服务配置一些属性
如:
其实我们可以发现,只要微服务命名规范,我们完全可以直接从nacos拿到服务名以及路径信息,配和knife4jAggregation的nacos配置,实现文档自动加载,即文档像同服务一起自动注册,自动下线。
通过阅读源码可得,knife4j的配置需要通过NacosRepository注入。
所以我们自己提供该类并注入配置即可
完整配置代码:
@Configuration
public class Knife4jConfig {
private static final Logger logger = LoggerFactory.getLogger(Knife4jConfig.class);
@Value("${knife4j.nacos.serviceUrl}")
String serverUrl;
@Value("${knife4j.nacos.namespaceId:}")
String namespaceId;
@Value("${knife4j.nacos.groupName:}")
String groupName;
private static final String FUNCTION_CODE = "knife4j";
private static final long LOOP_INTERVAL = 30000;//30s 刷新一次
private final NacosSetting nacosSetting = new NacosSetting();
NacosRepository nacosRepository;
@Bean(initMethod = "start",destroyMethod = "close")
public NacosRepository nacosRepository() {
nacosSetting.setEnable(true);
nacosSetting.setServiceUrl(serverUrl);
ArrayList<NacosRoute> nacosRoutes = buildRouters();
nacosSetting.setRoutes(nacosRoutes);
loopFlushConfig();
nacosRepository = new NacosRepository(nacosSetting);
return nacosRepository;
}
private NsServers loadNsService() {
String loadNsServiceUrl = serverUrl + "/v1/ns/service/list";
//默认聚合时只返回健康实例
Map<String, Object> params = new HashMap<>();
params.put("healthyOnly", true);
params.put("pageNo", 1);
params.put("pageSize", 9999);
if (StringUtils.hasLength(groupName)){
params.put("groupName", groupName);
}
if (StringUtils.hasLength(namespaceId)){
params.put("namespaceId", namespaceId);
}
String result = null;
try {
result = HttpClientUtils.doGet(loadNsServiceUrl, params, new HashMap<>());
} catch (IOException e) {
e.printStackTrace();
}
NsServers servers = JsonUtils.decode(result, NsServers.class);
return servers;
}
private List<InstanceResult> loadNsInstance(NsServers servers) {
String loadNsInstanceUrl = serverUrl + "/v1/ns/instance/list";
ExecutorService executorService = ThreadUtil.newExecutor(20);
List<InstanceResult> instanceList = new ArrayList<>(servers.getCount());
List<String> instanceNames = servers.getDoms();
for (String name : instanceNames) {
//默认聚合时只返回健康实例
Map<String, Object> params = new HashMap<>();
params.put("serviceName", name);
params.put("healthyOnly", true);
if (StringUtils.hasLength(groupName)){
params.put("groupName", groupName);
}
if (StringUtils.hasLength(namespaceId)){
params.put("namespaceId", namespaceId);
}
executorService.submit(()->{
String result = null;
try {
result = HttpClientUtils.doGet(loadNsInstanceUrl, params, new HashMap<>());
} catch (IOException e) {
e.printStackTrace();
}
InstanceResult instanceResult = JSONUtil.toBean(result, InstanceResult.class);
instanceList.add(instanceResult);
});
}
executorService.shutdown(); //禁用提交的新任务
try {
if (!executorService.awaitTermination(30, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow(); //(重新)取消当前线程是否中断
Thread.currentThread().interrupt(); //保持中断状态
}
return instanceList;
}
private ArrayList<NacosRoute> buildRouters() {
ArrayList<NacosRoute> nsRoutes = new ArrayList<>();
NsServers nsServers = loadNsService();
List<InstanceResult> nsInstance = loadNsInstance(nsServers);
for (InstanceResult result : nsInstance) {
String dom = result.getDom();
NacosRoute nacosRoute = new NacosRoute();
nacosRoute.setNamespaceId(namespaceId);
nacosRoute.setServiceName(dom);
nacosRoute.setLocation(dom + "/v3/api-docs?group=default");
nsRoutes.add(nacosRoute);
}
return nsRoutes;
}
private void loopFlushConfig() {
new Thread(()-> {
while (true) {
try {
ThreadUtil.sleep(LOOP_INTERVAL);
List<NacosRoute> nacosRoutes = buildRouters();
nacosSetting.setRoutes(nacosRoutes);
//此处需要修改源码 将在下方给出修改方式
nacosRepository.initNacos(nacosSetting);
nacosRepository.applyRoutes(nacosSetting);
logger.debug("=======knife4j 配置刷新==============");
} catch (Exception e) {
logger.error("knife4j 配置刷新异常", e);
}
}
}).start();
}
}
该段代码实现了通过nacos自动加载服务信息并注入knife4j。同一个集群中的项目仅需要配置swagger,而无需加任何其它配置,则可与knife4j无缝集成
源码修改
knife4j本身不支持动态刷新配置,需要稍微调整源码才可实现。 本修改案例基于knife4j-aggregation-spring-boot-starter 2.0.9。 修改步骤如下
1.下载源码
2.进入com.github.xiaoymin.knife4j.aggre.repository.NacosRepository
3.将applyRoutes 和 initNacos 方法修饰符改为public
打包编译,发布在自己的私服或手动上传至maven库