mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-12 07:02:14 +08:00
优化文档刷新逻辑
This commit is contained in:
@@ -288,7 +288,7 @@ public class ZookeeperContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听一个节点
|
* 监听一个临时节点
|
||||||
*
|
*
|
||||||
* @param path
|
* @param path
|
||||||
* @param listenCallback 回调
|
* @param listenCallback 回调
|
||||||
|
@@ -8,4 +8,9 @@ public class ServiceConstants {
|
|||||||
* zookeeper存放接口路由信息的根目录
|
* zookeeper存放接口路由信息的根目录
|
||||||
*/
|
*/
|
||||||
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
|
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务临时节点
|
||||||
|
*/
|
||||||
|
public static final String SOP_SERVICE_TEMP_PATH = "/com.gitee.sop.service.tmp";
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import org.apache.commons.lang.math.NumberUtils;
|
|||||||
import org.apache.curator.framework.CuratorFramework;
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
import org.apache.curator.retry.ExponentialBackoffRetry;
|
import org.apache.curator.retry.ExponentialBackoffRetry;
|
||||||
|
import org.apache.zookeeper.CreateMode;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
@@ -94,6 +95,23 @@ public class ZookeeperTool implements Closeable {
|
|||||||
.forPath(path, data.getBytes());
|
.forPath(path, data.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建临时序列节点
|
||||||
|
* @param path 节点路径
|
||||||
|
* @param data 数据
|
||||||
|
* @return 返回节点路径
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public String createOrUpdateEphemeralSequentialPath(String path, String data) throws Exception {
|
||||||
|
return getClient().create()
|
||||||
|
// 如果节点存在则Curator将会使用给出的数据设置这个节点的值
|
||||||
|
.orSetData()
|
||||||
|
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
|
||||||
|
.creatingParentContainersIfNeeded()
|
||||||
|
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
|
||||||
|
.forPath(path, data.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新建或保存节点
|
* 新建或保存节点
|
||||||
*
|
*
|
||||||
|
@@ -10,7 +10,6 @@ import com.gitee.sop.servercommon.route.ServiceRouteInfo;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.util.DigestUtils;
|
import org.springframework.util.DigestUtils;
|
||||||
@@ -81,6 +80,7 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
|||||||
String nodeData = JSON.toJSONString(serviceRouteInfo);
|
String nodeData = JSON.toJSONString(serviceRouteInfo);
|
||||||
log.info("serviceId:{}, zookeeper保存路径:{}", serviceId, savePath);
|
log.info("serviceId:{}, zookeeper保存路径:{}", serviceId, savePath);
|
||||||
this.zookeeperTool.createPath(savePath, nodeData);
|
this.zookeeperTool.createPath(savePath, nodeData);
|
||||||
|
this.zookeeperTool.createPath(serviceRouteInfo.getZookeeperTempServiceIdPath(), "");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalStateException("zookeeper操作失败");
|
throw new IllegalStateException("zookeeper操作失败");
|
||||||
}
|
}
|
||||||
@@ -91,8 +91,11 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
|||||||
try {
|
try {
|
||||||
ServiceRouteInfo serviceRouteInfo = this.buildServiceGatewayInfo(serviceApiInfo);
|
ServiceRouteInfo serviceRouteInfo = this.buildServiceGatewayInfo(serviceApiInfo);
|
||||||
this.uploadServiceRouteInfoToZookeeper(serviceRouteInfo);
|
this.uploadServiceRouteInfoToZookeeper(serviceRouteInfo);
|
||||||
} finally {
|
// 同时上传一个临时节点
|
||||||
IOUtils.closeQuietly(zookeeperTool);
|
String tempPath = serviceRouteInfo.getZookeeperTempServiceIdChildPath();
|
||||||
|
this.zookeeperTool.createOrUpdateEphemeralSequentialPath(tempPath, JSON.toJSONString(serviceRouteInfo));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("上传一个临时节点失败, serviceApiInfo:{}", serviceApiInfo, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
public class ServiceRouteInfo {
|
public class ServiceRouteInfo {
|
||||||
private static final String SOP_SERVICE_ROUTE_PATH = ServiceConstants.SOP_SERVICE_ROUTE_PATH;
|
private static final String SOP_SERVICE_ROUTE_PATH = ServiceConstants.SOP_SERVICE_ROUTE_PATH;
|
||||||
|
private static final String SOP_SERVICE_TEMP_PATH = ServiceConstants.SOP_SERVICE_TEMP_PATH;
|
||||||
|
|
||||||
/** 服务名称,对应spring.application.name */
|
/** 服务名称,对应spring.application.name */
|
||||||
private String serviceId;
|
private String serviceId;
|
||||||
@@ -39,4 +40,22 @@ public class ServiceRouteInfo {
|
|||||||
public String getZookeeperPath() {
|
public String getZookeeperPath() {
|
||||||
return SOP_SERVICE_ROUTE_PATH + '/' + serviceId;
|
return SOP_SERVICE_ROUTE_PATH + '/' + serviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回zookeeper路径
|
||||||
|
* @return 返回zookeeper路径
|
||||||
|
*/
|
||||||
|
@JSONField(serialize = false)
|
||||||
|
public String getZookeeperTempServiceIdPath() {
|
||||||
|
return SOP_SERVICE_TEMP_PATH + '/' + serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回zookeeper路径
|
||||||
|
* @return 返回zookeeper路径
|
||||||
|
*/
|
||||||
|
@JSONField(serialize = false)
|
||||||
|
public String getZookeeperTempServiceIdChildPath() {
|
||||||
|
return getZookeeperTempServiceIdPath() + "/" + serviceId;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -31,7 +31,7 @@ public class OpenServiceConfig extends AlipayServiceConfiguration {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开启文档
|
* 开启文档,本地微服务文档地址:http://localhost:2222/doc.html
|
||||||
* http://ip:port/v2/api-docs
|
* http://ip:port/v2/api-docs
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@@ -31,4 +31,22 @@ public class CuratorTest extends TestCase {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除临时节点
|
||||||
|
*/
|
||||||
|
public void testDelTemp() {
|
||||||
|
String tempRoot = "/com.gitee.sop.service.tmp";
|
||||||
|
CuratorFramework client = CuratorFrameworkFactory.builder()
|
||||||
|
.connectString(zookeeperServerAddr)
|
||||||
|
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
client.start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.delete().deletingChildrenIfNeeded().forPath(tempRoot);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package com.gitee.sop.websiteserver.bean;
|
package com.gitee.sop.websiteserver.bean;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -10,5 +11,7 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
public class DocInfo {
|
public class DocInfo {
|
||||||
private String title;
|
private String title;
|
||||||
|
@JSONField(serialize = false)
|
||||||
|
private String serviceId;
|
||||||
private List<DocModule> docModuleList;
|
private List<DocModule> docModuleList;
|
||||||
}
|
}
|
||||||
|
@@ -8,4 +8,9 @@ public class WebsiteConstants {
|
|||||||
* zookeeper存放接口路由信息的根目录
|
* zookeeper存放接口路由信息的根目录
|
||||||
*/
|
*/
|
||||||
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
|
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务临时节点
|
||||||
|
*/
|
||||||
|
public static final String SOP_SERVICE_TEMP_PATH = "/com.gitee.sop.service.tmp";
|
||||||
}
|
}
|
||||||
|
@@ -5,11 +5,18 @@ import org.apache.commons.lang.StringUtils;
|
|||||||
import org.apache.commons.lang.math.NumberUtils;
|
import org.apache.commons.lang.math.NumberUtils;
|
||||||
import org.apache.curator.framework.CuratorFramework;
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
|
import org.apache.curator.framework.recipes.cache.ChildData;
|
||||||
|
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
|
||||||
|
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
|
||||||
import org.apache.curator.framework.recipes.cache.TreeCache;
|
import org.apache.curator.framework.recipes.cache.TreeCache;
|
||||||
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
|
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
|
||||||
import org.apache.curator.retry.ExponentialBackoffRetry;
|
import org.apache.curator.retry.ExponentialBackoffRetry;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tanghc
|
* @author tanghc
|
||||||
@@ -50,6 +57,10 @@ public class ZookeeperContext {
|
|||||||
return WebsiteConstants.SOP_SERVICE_ROUTE_PATH;
|
return WebsiteConstants.SOP_SERVICE_ROUTE_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getServiceTempRootPath() {
|
||||||
|
return WebsiteConstants.SOP_SERVICE_TEMP_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
public static CuratorFramework getClient() {
|
public static CuratorFramework getClient() {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
@@ -58,10 +69,99 @@ public class ZookeeperContext {
|
|||||||
ZookeeperContext.client = client;
|
ZookeeperContext.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPathExist(String path) {
|
||||||
|
try {
|
||||||
|
return client.checkExists().forPath(path) != null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有子节点
|
||||||
|
* @param parentPath
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static boolean hasChildren(String parentPath) throws Exception {
|
||||||
|
List<String> children = client.getChildren().forPath(parentPath);
|
||||||
|
return !CollectionUtils.isEmpty(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建path,如果path存在不报错,静默返回path名称
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String createPath(String path, String data) throws Exception {
|
||||||
|
if (isPathExist(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return getClient().create()
|
||||||
|
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
|
||||||
|
.creatingParentContainersIfNeeded()
|
||||||
|
.forPath(path, data.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取子节点信息并监听子节点
|
||||||
|
*
|
||||||
|
* @param parentPath 父节点路径
|
||||||
|
* @param listConsumer 子节点数据
|
||||||
|
* @param listener 监听事件
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static void getChildrenAndListen(String parentPath, Consumer<List<ChildData>> listConsumer, PathChildrenCacheListener listener) throws Exception {
|
||||||
|
// 为子节点添加watcher
|
||||||
|
// PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件
|
||||||
|
PathChildrenCache childrenCache = new PathChildrenCache(client, parentPath, true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StartMode: 初始化方式
|
||||||
|
* POST_INITIALIZED_EVENT:异步初始化,初始化之后会触发事件
|
||||||
|
* NORMAL:异步初始化
|
||||||
|
* BUILD_INITIAL_CACHE:同步初始化
|
||||||
|
*/
|
||||||
|
childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
|
||||||
|
|
||||||
|
// 列出子节点数据列表,需要使用BUILD_INITIAL_CACHE同步初始化模式才能获得,异步是获取不到的
|
||||||
|
List<ChildData> childDataList = childrenCache.getCurrentData();
|
||||||
|
listConsumer.accept(childDataList);
|
||||||
|
log.info("监听子节点增删改,监听路径:{}", parentPath);
|
||||||
|
// 监听根节点下面的子节点
|
||||||
|
childrenCache.getListenable().addListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听子节点的增删改
|
||||||
|
*
|
||||||
|
* @param parentPath 父节点路径
|
||||||
|
* @param listener
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static void listenChildren(String parentPath, PathChildrenCacheListener listener) throws Exception {
|
||||||
|
// 为子节点添加watcher
|
||||||
|
// PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件
|
||||||
|
PathChildrenCache childrenCache = new PathChildrenCache(client, parentPath, true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StartMode: 初始化方式
|
||||||
|
* POST_INITIALIZED_EVENT:异步初始化,初始化之后会触发事件
|
||||||
|
* NORMAL:异步初始化
|
||||||
|
* BUILD_INITIAL_CACHE:同步初始化
|
||||||
|
*/
|
||||||
|
childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
|
||||||
|
// 监听根节点下面的子节点
|
||||||
|
childrenCache.getListenable().addListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听子节点,可以自定义层级
|
* 监听子节点,可以自定义层级
|
||||||
* @param parentPath 父节点路径
|
* @param parentPath 父节点路径
|
||||||
* @param maxDepth 层级,从1开始。比如当前监听节点/t1,目录最深为/t1/t2/t3/t4,则maxDepth=3,说明下面3级子目录全
|
* @param maxDepth 层级,从1开始。比如当前监听节点/t1,目录最深为/t1/t2/t3/t4,则maxDepth=3,说明下面3级子目录全部监听
|
||||||
* @param listener
|
* @param listener
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@@ -73,7 +173,6 @@ public class ZookeeperContext {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
treeCache.getListenable().addListener(listener);
|
treeCache.getListenable().addListener(listener);
|
||||||
//没有开启模式作为入参的方法
|
|
||||||
treeCache.start();
|
treeCache.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package com.gitee.sop.websiteserver.controller;
|
package com.gitee.sop.websiteserver.controller;
|
||||||
|
|
||||||
import com.gitee.sop.websiteserver.bean.DocInfo;
|
import com.gitee.sop.websiteserver.bean.DocInfo;
|
||||||
import com.gitee.sop.websiteserver.bean.DocItem;
|
|
||||||
import com.gitee.sop.websiteserver.manager.DocManager;
|
import com.gitee.sop.websiteserver.manager.DocManager;
|
||||||
import com.gitee.sop.websiteserver.vo.DocBaseInfoVO;
|
import com.gitee.sop.websiteserver.vo.DocBaseInfoVO;
|
||||||
import com.gitee.sop.websiteserver.vo.DocInfoVO;
|
import com.gitee.sop.websiteserver.vo.DocInfoVO;
|
||||||
@@ -59,11 +58,6 @@ public class DocController {
|
|||||||
return docManager.getByTitle(title);
|
return docManager.getByTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/item/{method}/{version}/")
|
|
||||||
public DocItem getDocItem(@PathVariable("method") String method, @PathVariable("version") String version) {
|
|
||||||
return docManager.get(method, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 后门地址,可手动更新文档内容,一般情况下用不到
|
// 后门地址,可手动更新文档内容,一般情况下用不到
|
||||||
@GetMapping("/reload")
|
@GetMapping("/reload")
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package com.gitee.sop.websiteserver.manager;
|
package com.gitee.sop.websiteserver.manager;
|
||||||
|
|
||||||
import com.gitee.sop.websiteserver.bean.DocInfo;
|
import com.gitee.sop.websiteserver.bean.DocInfo;
|
||||||
import com.gitee.sop.websiteserver.bean.DocItem;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@@ -12,8 +11,6 @@ public interface DocManager {
|
|||||||
|
|
||||||
void load(String serviceId);
|
void load(String serviceId);
|
||||||
|
|
||||||
DocItem get(String method, String version);
|
|
||||||
|
|
||||||
DocInfo getByTitle(String title);
|
DocInfo getByTitle(String title);
|
||||||
|
|
||||||
Collection<DocInfo> listAll();
|
Collection<DocInfo> listAll();
|
||||||
|
@@ -7,12 +7,12 @@ import com.gitee.sop.registryapi.bean.ServiceInfo;
|
|||||||
import com.gitee.sop.registryapi.bean.ServiceInstance;
|
import com.gitee.sop.registryapi.bean.ServiceInstance;
|
||||||
import com.gitee.sop.registryapi.service.RegistryService;
|
import com.gitee.sop.registryapi.service.RegistryService;
|
||||||
import com.gitee.sop.websiteserver.bean.DocInfo;
|
import com.gitee.sop.websiteserver.bean.DocInfo;
|
||||||
import com.gitee.sop.websiteserver.bean.DocItem;
|
|
||||||
import com.gitee.sop.websiteserver.bean.ZookeeperContext;
|
import com.gitee.sop.websiteserver.bean.ZookeeperContext;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
import org.apache.commons.lang3.math.NumberUtils;
|
||||||
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
|
import org.apache.curator.framework.recipes.cache.ChildData;
|
||||||
|
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
@@ -43,21 +43,17 @@ import java.util.stream.Collectors;
|
|||||||
public class DocManagerImpl implements DocManager {
|
public class DocManagerImpl implements DocManager {
|
||||||
|
|
||||||
// key:title
|
// key:title
|
||||||
Map<String, DocInfo> docDefinitionMap = new HashMap<>();
|
private Map<String, DocInfo> docDefinitionMap = new HashMap<>();
|
||||||
|
|
||||||
// key: name+version
|
private RestTemplate restTemplate = new RestTemplate();
|
||||||
Map<String, DocItem> docItemMap = new HashMap<>();
|
|
||||||
|
|
||||||
|
private DocParser swaggerDocParser = new SwaggerDocParser();
|
||||||
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
private DocParser easyopenDocParser = new EasyopenDocParser();
|
||||||
|
|
||||||
DocParser swaggerDocParser = new SwaggerDocParser();
|
private ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
DocParser easyopenDocParser = new EasyopenDocParser();
|
private DelayQueue<Msg> queue = new DelayQueue<>();
|
||||||
|
|
||||||
ExecutorService executorService = Executors.newSingleThreadExecutor();
|
|
||||||
|
|
||||||
DelayQueue<Msg> queue = new DelayQueue<>();
|
|
||||||
|
|
||||||
private String secret = "b749a2ec000f4f29";
|
private String secret = "b749a2ec000f4f29";
|
||||||
|
|
||||||
@@ -70,14 +66,10 @@ public class DocManagerImpl implements DocManager {
|
|||||||
@Value("${doc.refresh-seconds:60}")
|
@Value("${doc.refresh-seconds:60}")
|
||||||
private String refreshSeconds;
|
private String refreshSeconds;
|
||||||
|
|
||||||
private volatile boolean listenInited;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(String serviceId) {
|
public void load(String serviceId) {
|
||||||
try {
|
try {
|
||||||
List<ServiceInfo> serviceInfoList = registryService.listAllService(1, 9999);
|
List<ServiceInfo> serviceInfoList = registryService.listAllService(1, 9999);
|
||||||
log.info("服务列表:{}", serviceInfoList);
|
|
||||||
|
|
||||||
serviceInfoList
|
serviceInfoList
|
||||||
.stream()
|
.stream()
|
||||||
// 网关没有文档提供,需要排除
|
// 网关没有文档提供,需要排除
|
||||||
@@ -110,6 +102,7 @@ public class DocManagerImpl implements DocManager {
|
|||||||
JSONObject docRoot = JSON.parseObject(docInfoJson, Feature.OrderedField, Feature.DisableCircularReferenceDetect);
|
JSONObject docRoot = JSON.parseObject(docInfoJson, Feature.OrderedField, Feature.DisableCircularReferenceDetect);
|
||||||
DocParser docParser = this.buildDocParser(docRoot);
|
DocParser docParser = this.buildDocParser(docRoot);
|
||||||
DocInfo docInfo = docParser.parseJson(docRoot);
|
DocInfo docInfo = docParser.parseJson(docRoot);
|
||||||
|
docInfo.setServiceId(serviceInstance.getServiceId());
|
||||||
docDefinitionMap.put(docInfo.getTitle(), docInfo);
|
docDefinitionMap.put(docInfo.getTitle(), docInfo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 这里报错可能是因为有些微服务没有配置swagger文档,导致404访问不到
|
// 这里报错可能是因为有些微服务没有配置swagger文档,导致404访问不到
|
||||||
@@ -134,11 +127,6 @@ public class DocManagerImpl implements DocManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DocItem get(String method, String version) {
|
|
||||||
return docItemMap.get(method + version);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DocInfo getByTitle(String title) {
|
public DocInfo getByTitle(String title) {
|
||||||
return docDefinitionMap.get(title);
|
return docDefinitionMap.get(title);
|
||||||
@@ -164,28 +152,73 @@ public class DocManagerImpl implements DocManager {
|
|||||||
executorService.execute(new Consumer(queue, this));
|
executorService.execute(new Consumer(queue, this));
|
||||||
|
|
||||||
ZookeeperContext.setEnvironment(environment);
|
ZookeeperContext.setEnvironment(environment);
|
||||||
String routeRootPath = ZookeeperContext.getRouteRootPath();
|
String serviceTempRootPath = ZookeeperContext.getServiceTempRootPath();
|
||||||
|
ZookeeperContext.createPath(serviceTempRootPath, "{}");
|
||||||
// 如果节点内容有变化则自动更新文档
|
// 如果节点内容有变化则自动更新文档
|
||||||
ZookeeperContext.listenChildren(routeRootPath, 1, (client, event) -> {
|
|
||||||
if (listenInited) {
|
ZookeeperContext.getChildrenAndListen(serviceTempRootPath, childDataList -> {
|
||||||
|
for (ChildData childData : childDataList) {
|
||||||
|
String serviceIdPath = childData.getPath();
|
||||||
|
try {
|
||||||
|
boolean hasChildren = ZookeeperContext.hasChildren(serviceIdPath);
|
||||||
|
if (hasChildren) {
|
||||||
|
log.info("加载文档服务器,path:{}", serviceIdPath);
|
||||||
|
listenServiceIdPath(serviceIdPath);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("监听路径失败,serviceIdPath:{}", serviceIdPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, (client, event) -> {
|
||||||
|
PathChildrenCacheEvent.Type type = event.getType();
|
||||||
|
if (type == PathChildrenCacheEvent.Type.CHILD_ADDED) {
|
||||||
|
String serviceIdPath = event.getData().getPath();
|
||||||
|
log.info("新增文档服务器,path:{}", serviceIdPath);
|
||||||
|
listenServiceIdPath(serviceIdPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void listenServiceIdPath(String serviceIdPath) throws Exception {
|
||||||
|
ZookeeperContext.listenChildren(serviceIdPath, (client, event) -> {
|
||||||
|
String path = event.getData().getPath();
|
||||||
|
PathChildrenCacheEvent.Type type = event.getType();
|
||||||
|
log.info("服务节点变更,path:{}, eventType:{}", path, event.getType().name());
|
||||||
|
if (type == PathChildrenCacheEvent.Type.CHILD_ADDED
|
||||||
|
|| type == PathChildrenCacheEvent.Type.CHILD_UPDATED) {
|
||||||
|
byte[] data = event.getData().getData();
|
||||||
|
String serviceInfoJson = new String(data);
|
||||||
|
if (StringUtils.isEmpty(serviceInfoJson)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ZKServiceInfo serviceInfo = JSON.parseObject(serviceInfoJson, ZKServiceInfo.class);
|
||||||
|
String serviceId = serviceInfo.getServiceId();
|
||||||
|
int delaySeconds = NumberUtils.toInt(refreshSeconds, 60);
|
||||||
|
log.info("微服务[{}]推送更新,{}秒后加载文档内容", serviceId, delaySeconds);
|
||||||
long id = System.currentTimeMillis();
|
long id = System.currentTimeMillis();
|
||||||
|
Msg msg = new Msg(id, delaySeconds * 1000);
|
||||||
|
msg.serviceId = serviceId;
|
||||||
|
// 延迟20秒执行
|
||||||
|
queue.offer(msg);
|
||||||
|
} else if (event.getType() == PathChildrenCacheEvent.Type.CHILD_REMOVED) {
|
||||||
byte[] data = event.getData().getData();
|
byte[] data = event.getData().getData();
|
||||||
String serviceInfoJson = new String(data);
|
String serviceInfoJson = new String(data);
|
||||||
ZKServiceInfo serviceInfo = JSON.parseObject(serviceInfoJson, ZKServiceInfo.class);
|
ZKServiceInfo serviceInfo = JSON.parseObject(serviceInfoJson, ZKServiceInfo.class);
|
||||||
String serviceId = serviceInfo.getServiceId();
|
String serviceId = serviceInfo.getServiceId();
|
||||||
log.info("微服务[{}]推送更新", serviceId);
|
boolean hasChildren = ZookeeperContext.hasChildren(serviceIdPath);
|
||||||
Msg msg = new Msg(id, 1000 * NumberUtils.toInt(refreshSeconds, 60));
|
// 如果没有子节点就删除
|
||||||
msg.serviceId = serviceId;
|
if (!hasChildren) {
|
||||||
// 延迟20秒执行
|
log.info("服务节点已删除,删除对应文档信息,path:{}", event.getData().getPath());
|
||||||
queue.offer(msg);
|
removeDoc(serviceId);
|
||||||
}
|
}
|
||||||
TreeCacheEvent.Type type = event.getType();
|
|
||||||
if (type == TreeCacheEvent.Type.INITIALIZED) {
|
|
||||||
listenInited = true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeDoc(String serviceId) {
|
||||||
|
docDefinitionMap.entrySet().removeIf(entry -> serviceId.equalsIgnoreCase(entry.getValue().getServiceId()));
|
||||||
|
}
|
||||||
|
|
||||||
static class Msg implements Delayed {
|
static class Msg implements Delayed {
|
||||||
private long id;
|
private long id;
|
||||||
private long delay;
|
private long delay;
|
||||||
@@ -202,8 +235,7 @@ public class DocManagerImpl implements DocManager {
|
|||||||
@Override
|
@Override
|
||||||
public int compareTo(Delayed delayed) {
|
public int compareTo(Delayed delayed) {
|
||||||
Msg msg = (Msg) delayed;
|
Msg msg = (Msg) delayed;
|
||||||
return Long.valueOf(this.id) > Long.valueOf(msg.id) ? 1
|
return Long.compare(this.id, msg.id);
|
||||||
: (Long.valueOf(this.id) < Long.valueOf(msg.id) ? -1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 延迟任务是否到时就是按照这个方法判断如果返回的是负数则说明到期否则还没到期
|
// 延迟任务是否到时就是按照这个方法判断如果返回的是负数则说明到期否则还没到期
|
||||||
|
Reference in New Issue
Block a user