mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
适配eureka
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
## 2.2.0
|
||||
|
||||
- 支持eureka注册中心,需要执行`sop-2.2.0.sql`升级文件
|
||||
- 签名内容支持urlencode(设置`sign.urlencode=true`)
|
||||
|
||||
## 2.1.3
|
||||
|
||||
|
@@ -8,15 +8,17 @@ import com.gitee.sop.gatewaycommon.limit.LimitManager;
|
||||
import com.gitee.sop.gatewaycommon.loadbalancer.SopPropertiesFactory;
|
||||
import com.gitee.sop.gatewaycommon.message.ErrorFactory;
|
||||
import com.gitee.sop.gatewaycommon.param.ParameterFormatter;
|
||||
import com.gitee.sop.gatewaycommon.route.EurekaRoutesListener;
|
||||
import com.gitee.sop.gatewaycommon.route.NacosRoutesListener;
|
||||
import com.gitee.sop.gatewaycommon.route.ServiceRouteListener;
|
||||
import com.gitee.sop.gatewaycommon.route.EurekaRegistryListener;
|
||||
import com.gitee.sop.gatewaycommon.route.NacosRegistryListener;
|
||||
import com.gitee.sop.gatewaycommon.route.RegistryListener;
|
||||
import com.gitee.sop.gatewaycommon.route.ServiceListener;
|
||||
import com.gitee.sop.gatewaycommon.secret.IsvManager;
|
||||
import com.gitee.sop.gatewaycommon.session.SessionManager;
|
||||
import com.gitee.sop.gatewaycommon.validate.SignConfig;
|
||||
import com.gitee.sop.gatewaycommon.validate.Validator;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
|
||||
@@ -72,13 +74,19 @@ public class AbstractConfiguration implements ApplicationContextAware {
|
||||
@Bean
|
||||
@ConditionalOnProperty("spring.cloud.nacos.discovery.server-addr")
|
||||
RegistryListener registryListenerNacos() {
|
||||
return new NacosRoutesListener();
|
||||
return new NacosRegistryListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty("eureka.client.serviceUrl.defaultZone")
|
||||
RegistryListener registryListenerEureka() {
|
||||
return new EurekaRoutesListener();
|
||||
return new EurekaRegistryListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ServiceListener serviceListener() {
|
||||
return new ServiceRouteListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -174,6 +182,14 @@ public class AbstractConfiguration implements ApplicationContextAware {
|
||||
if (RouteRepositoryContext.getRouteRepository() == null) {
|
||||
throw new IllegalArgumentException("RouteRepositoryContext.setRouteRepository()方法未使用");
|
||||
}
|
||||
String serverName = environment.getProperty("spring.application.name");
|
||||
if (!"api-gateway".equals(serverName)) {
|
||||
throw new IllegalArgumentException("spring.application.name必须为api-gateway");
|
||||
}
|
||||
String urlencode = environment.getProperty("sign.urlencode");
|
||||
if ("true".equals(urlencode)) {
|
||||
SignConfig.enableUrlencodeMode();
|
||||
}
|
||||
EnvironmentContext.setEnvironment(environment);
|
||||
|
||||
initMessage();
|
||||
|
@@ -14,7 +14,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* 用不到了
|
||||
* 用不到了,这个类的作用是监听消息推送用的。由admin推送一条config配置,然后这里触发事件。
|
||||
* 现在改为直接由admin请求网关提供的接口进行配置修改。
|
||||
* 考虑
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
|
@@ -0,0 +1,68 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseRegistryListener implements RegistryListener {
|
||||
|
||||
private static final int FIVE_SECONDS = 1000 * 5;
|
||||
|
||||
private Map<String, Long> updateTimeMap = new ConcurrentHashMap<>(16);
|
||||
|
||||
public static List<String> EXCLUDE_SERVICE_ID_LIST = new ArrayList<>(8);
|
||||
|
||||
static {
|
||||
EXCLUDE_SERVICE_ID_LIST.add("api-gateway");
|
||||
EXCLUDE_SERVICE_ID_LIST.add("website-server");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ServiceListener serviceListener;
|
||||
|
||||
/**
|
||||
* 移除路由信息
|
||||
*
|
||||
* @param serviceId serviceId
|
||||
*/
|
||||
public void removeRoutes(String serviceId) {
|
||||
serviceListener.onRemoveService(serviceId.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取路由信息
|
||||
*
|
||||
* @param instance 服务实例
|
||||
*/
|
||||
public void pullRoutes(InstanceDefinition instance) {
|
||||
// serviceId统一小写
|
||||
instance.setServiceId(instance.getServiceId().toLowerCase());
|
||||
serviceListener.onAddInstance(instance);
|
||||
}
|
||||
|
||||
protected boolean canOperator(String serviceId) {
|
||||
for (String excludeServiceId : EXCLUDE_SERVICE_ID_LIST) {
|
||||
if (excludeServiceId.equalsIgnoreCase(serviceId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// nacos会不停的触发事件,这里做了一层拦截
|
||||
// 同一个serviceId5秒内允许访问一次
|
||||
Long lastUpdateTime = updateTimeMap.getOrDefault(serviceId, 0L);
|
||||
long now = System.currentTimeMillis();
|
||||
boolean can = now - lastUpdateTime > FIVE_SECONDS;
|
||||
if (can) {
|
||||
updateTimeMap.put(serviceId, now);
|
||||
}
|
||||
return can;
|
||||
}
|
||||
}
|
@@ -1,154 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.manager.BaseRouteCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseRoutesListener implements RegistryListener {
|
||||
|
||||
private static final String SOP_ROUTES_PATH = "/sop/routes";
|
||||
|
||||
private static final String SECRET = "a3d9sf!1@odl90zd>fkASwq";
|
||||
|
||||
private static final int FIVE_SECONDS = 1000 * 5;
|
||||
|
||||
private static final String METADATA_SERVER_CONTEXT_PATH = "server.servlet.context-path";
|
||||
|
||||
private static final String METADATA_SOP_ROUTES_PATH = "sop.routes.path";
|
||||
|
||||
private static RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
static {
|
||||
// 解决statusCode不等于200,就抛异常问题
|
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||
@Override
|
||||
protected boolean hasError(HttpStatus statusCode) {
|
||||
return statusCode == null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Map<String, Long> updateTimeMap = new ConcurrentHashMap<>(16);
|
||||
|
||||
@Autowired
|
||||
private BaseRouteCache<?> baseRouteCache;
|
||||
|
||||
@Autowired
|
||||
private RoutesProcessor routesProcessor;
|
||||
|
||||
/**
|
||||
* 移除路由信息
|
||||
*
|
||||
* @param serviceId serviceId
|
||||
*/
|
||||
public void removeRoutes(String serviceId) {
|
||||
doOperator(serviceId, () -> {
|
||||
log.info("服务下线,删除路由配置,serviceId: {}", serviceId);
|
||||
baseRouteCache.remove(serviceId);
|
||||
routesProcessor.removeAllRoutes(serviceId);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取路由信息
|
||||
*
|
||||
* @param instance 服务实例
|
||||
*/
|
||||
public void pullRoutes(InstanceDefinition instance) {
|
||||
String serviceName = instance.getServiceId();
|
||||
doOperator(serviceName, () -> {
|
||||
String url = getRouteRequestUrl(instance);
|
||||
log.info("拉取路由配置,serviceId: {}, url: {}", serviceName, url);
|
||||
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
String body = responseEntity.getBody();
|
||||
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class);
|
||||
baseRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance));
|
||||
} else {
|
||||
log.error("拉取路由配置异常,url: {}, status: {}, body: {}", url, responseEntity.getStatusCodeValue(), responseEntity.getBody());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void doOperator(String serviceId, Runnable runnable) {
|
||||
if (canOperator(serviceId)) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canOperator(String serviceId) {
|
||||
// nacos会不停的触发事件,这里做了一层拦截
|
||||
// 同一个serviceId5秒内允许访问一次
|
||||
Long lastUpdateTime = updateTimeMap.getOrDefault(serviceId, 0L);
|
||||
long now = System.currentTimeMillis();
|
||||
boolean can = now - lastUpdateTime > FIVE_SECONDS;
|
||||
if (can) {
|
||||
updateTimeMap.put(serviceId, now);
|
||||
}
|
||||
return can;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取路由请求url
|
||||
*
|
||||
* @param instance 服务实例
|
||||
* @return 返回最终url
|
||||
*/
|
||||
private static String getRouteRequestUrl(InstanceDefinition instance) {
|
||||
Map<String, String> metadata = instance.getMetadata();
|
||||
String customPath = metadata.get(METADATA_SOP_ROUTES_PATH);
|
||||
String homeUrl;
|
||||
String servletPath;
|
||||
// 如果metadata中指定了获取路由的url
|
||||
if (StringUtils.isNotBlank(customPath)) {
|
||||
// 自定义完整的url
|
||||
if (customPath.startsWith("http")) {
|
||||
homeUrl = customPath;
|
||||
servletPath = "";
|
||||
} else {
|
||||
homeUrl = getHomeUrl(instance);
|
||||
servletPath = customPath;
|
||||
}
|
||||
} else {
|
||||
// 默认处理
|
||||
homeUrl = getHomeUrl(instance);
|
||||
String contextPath = metadata.getOrDefault(METADATA_SERVER_CONTEXT_PATH, "");
|
||||
servletPath = contextPath + SOP_ROUTES_PATH;
|
||||
}
|
||||
if (StringUtils.isNotBlank(servletPath) && !servletPath.startsWith("/")) {
|
||||
servletPath = '/' + servletPath;
|
||||
}
|
||||
String query = buildQuery(SECRET);
|
||||
return homeUrl + servletPath + query;
|
||||
}
|
||||
|
||||
private static String getHomeUrl(InstanceDefinition instance) {
|
||||
return "http://" + instance.getIp() + ":" + instance.getPort();
|
||||
}
|
||||
|
||||
private static String buildQuery(String secret) {
|
||||
String time = String.valueOf(System.currentTimeMillis());
|
||||
String source = secret + time + secret;
|
||||
String sign = DigestUtils.md5DigestAsHex(source.getBytes());
|
||||
return "?time=" + time + "&sign=" + sign;
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public abstract class BaseServiceListener implements ServiceListener {
|
||||
|
||||
private static final String SECRET = "a3d9sf!1@odl90zd>fkASwq";
|
||||
|
||||
private static RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
static {
|
||||
// 解决statusCode不等于200,就抛异常问题
|
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||
@Override
|
||||
protected boolean hasError(HttpStatus statusCode) {
|
||||
return statusCode == null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected static String buildQuery(String secret) {
|
||||
String time = String.valueOf(System.currentTimeMillis());
|
||||
String source = secret + time + secret;
|
||||
String sign = DigestUtils.md5DigestAsHex(source.getBytes());
|
||||
return "?time=" + time + "&sign=" + sign;
|
||||
}
|
||||
|
||||
protected static String buildQuery() {
|
||||
return buildQuery(SECRET);
|
||||
}
|
||||
|
||||
public static RestTemplate getRestTemplate() {
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
@@ -7,7 +7,6 @@ import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.shared.Application;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@@ -22,7 +21,7 @@ import java.util.stream.Collectors;
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
public class EurekaRoutesListener extends BaseRoutesListener {
|
||||
public class EurekaRegistryListener extends BaseRegistryListener {
|
||||
|
||||
static {
|
||||
System.setProperty(SopPropertiesFactory.PROPERTIES_KEY, EurekaEnvironmentServerChooser.class.getName());
|
||||
@@ -30,9 +29,6 @@ public class EurekaRoutesListener extends BaseRoutesListener {
|
||||
|
||||
private Set<String> cacheServices = new HashSet<>();
|
||||
|
||||
@Value("${spring.application.name:api-gateway}")
|
||||
private String appName;
|
||||
|
||||
@Override
|
||||
public void onEvent(ApplicationEvent applicationEvent) {
|
||||
Object source = applicationEvent.getSource();
|
||||
@@ -44,15 +40,19 @@ public class EurekaRoutesListener extends BaseRoutesListener {
|
||||
.map(Application::getName)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Set<String> currentServices = new HashSet<>(serviceList);
|
||||
final Set<String> currentServices = new HashSet<>(serviceList);
|
||||
currentServices.removeAll(cacheServices);
|
||||
// 如果有新的服务注册进来
|
||||
if (currentServices.size() > 0) {
|
||||
this.doRegister(registeredApplications, currentServices);
|
||||
List<Application> newApplications = registeredApplications.stream()
|
||||
.filter(application -> this.canOperator(application.getName())
|
||||
&& currentServices.contains(application.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
this.doRegister(newApplications);
|
||||
}
|
||||
|
||||
currentServices = new HashSet<>(serviceList);
|
||||
cacheServices.removeAll(currentServices);
|
||||
cacheServices.removeAll(new HashSet<>(serviceList));
|
||||
// 如果有服务删除
|
||||
if (cacheServices.size() > 0) {
|
||||
this.doRemove(cacheServices);
|
||||
@@ -61,12 +61,8 @@ public class EurekaRoutesListener extends BaseRoutesListener {
|
||||
cacheServices = new HashSet<>(serviceList);
|
||||
}
|
||||
|
||||
private void doRegister(List<Application> registeredApplications, Set<String> newServices) {
|
||||
registeredApplications
|
||||
.stream()
|
||||
.filter(application -> !appName.equalsIgnoreCase(application.getName())
|
||||
&& newServices.contains(application.getName()))
|
||||
.forEach(application -> {
|
||||
private void doRegister(List<Application> registeredApplications) {
|
||||
registeredApplications.forEach(application -> {
|
||||
List<InstanceInfo> instances = application.getInstances();
|
||||
if (CollectionUtils.isNotEmpty(instances)) {
|
||||
instances.sort(Comparator.comparing(InstanceInfo::getLastUpdatedTimestamp).reversed());
|
@@ -0,0 +1,71 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.alibaba.nacos.api.annotation.NacosInjected;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.NamingService;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 加载服务路由,nacos实现
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public class NacosRegistryListener extends BaseRegistryListener {
|
||||
|
||||
@Autowired
|
||||
private NacosDiscoveryProperties nacosDiscoveryProperties;
|
||||
|
||||
@NacosInjected
|
||||
private ConfigService configService;
|
||||
|
||||
@Override
|
||||
public void onEvent(ApplicationEvent applicationEvent) {
|
||||
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||
List<ServiceInfo> subscribes = null;
|
||||
try {
|
||||
subscribes = namingService.getSubscribeServices();
|
||||
} catch (NacosException e) {
|
||||
log.error("namingService.getSubscribeServices()错误", e);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(subscribes)) {
|
||||
return;
|
||||
}
|
||||
subscribes.stream()
|
||||
.filter(serviceInfo -> this.canOperator(serviceInfo.getName()))
|
||||
.forEach(serviceInfo -> {
|
||||
String serviceName = serviceInfo.getName();
|
||||
try {
|
||||
List<Instance> allInstances = namingService.getAllInstances(serviceName);
|
||||
if (CollectionUtils.isEmpty(allInstances)) {
|
||||
// 如果没有服务列表,则删除所有路由信息
|
||||
removeRoutes(serviceName);
|
||||
} else {
|
||||
for (Instance instance : allInstances) {
|
||||
InstanceDefinition instanceDefinition = new InstanceDefinition();
|
||||
instanceDefinition.setInstanceId(instance.getInstanceId());
|
||||
instanceDefinition.setServiceId(serviceName);
|
||||
instanceDefinition.setIp(instance.getIp());
|
||||
instanceDefinition.setPort(instance.getPort());
|
||||
instanceDefinition.setMetadata(instance.getMetadata());
|
||||
pullRoutes(instanceDefinition);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("选择服务实例失败,serviceName: {}", serviceName, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@@ -1,75 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.alibaba.nacos.api.annotation.NacosInjected;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.NamingService;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 加载服务路由,nacos实现
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public class NacosRoutesListener extends BaseRoutesListener {
|
||||
|
||||
@Autowired
|
||||
private NacosDiscoveryProperties nacosDiscoveryProperties;
|
||||
|
||||
@NacosInjected
|
||||
private ConfigService configService;
|
||||
|
||||
@Override
|
||||
public void onEvent(ApplicationEvent applicationEvent) {
|
||||
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||
List<ServiceInfo> subscribes = null;
|
||||
try {
|
||||
subscribes = namingService.getSubscribeServices();
|
||||
} catch (NacosException e) {
|
||||
log.error("namingService.getSubscribeServices()错误", e);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(subscribes)) {
|
||||
return;
|
||||
}
|
||||
// subscribe
|
||||
String thisServiceId = nacosDiscoveryProperties.getService();
|
||||
for (ServiceInfo serviceInfo : subscribes) {
|
||||
String serviceName = serviceInfo.getName();
|
||||
// 如果是本机服务,跳过
|
||||
if (Objects.equals(thisServiceId, serviceName)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
List<Instance> allInstances = namingService.getAllInstances(serviceName);
|
||||
if (CollectionUtils.isEmpty(allInstances)) {
|
||||
// 如果没有服务列表,则删除所有路由信息
|
||||
removeRoutes(serviceName);
|
||||
} else {
|
||||
for (Instance instance : allInstances) {
|
||||
InstanceDefinition instanceDefinition = new InstanceDefinition();
|
||||
instanceDefinition.setInstanceId(instance.getInstanceId());
|
||||
instanceDefinition.setServiceId(serviceName);
|
||||
instanceDefinition.setIp(instance.getIp());
|
||||
instanceDefinition.setPort(instance.getPort());
|
||||
instanceDefinition.setMetadata(instance.getMetadata());
|
||||
pullRoutes(instanceDefinition);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("选择服务实例失败,serviceName: {}", serviceName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface ServiceListener {
|
||||
void onRemoveService(String serviceId);
|
||||
|
||||
void onAddInstance(InstanceDefinition instance);
|
||||
}
|
@@ -0,0 +1,92 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.manager.BaseRouteCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public class ServiceRouteListener extends BaseServiceListener {
|
||||
|
||||
private static final String SOP_ROUTES_PATH = "/sop/routes";
|
||||
|
||||
private static final String METADATA_SERVER_CONTEXT_PATH = "server.servlet.context-path";
|
||||
|
||||
private static final String METADATA_SOP_ROUTES_PATH = "sop.routes.path";
|
||||
|
||||
@Autowired
|
||||
private BaseRouteCache<?> baseRouteCache;
|
||||
|
||||
@Autowired
|
||||
private RoutesProcessor routesProcessor;
|
||||
|
||||
@Override
|
||||
public void onRemoveService(String serviceId) {
|
||||
log.info("服务下线,删除路由配置,serviceId: {}", serviceId);
|
||||
baseRouteCache.remove(serviceId);
|
||||
routesProcessor.removeAllRoutes(serviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddInstance(InstanceDefinition instance) {
|
||||
String serviceName = instance.getServiceId();
|
||||
String url = getRouteRequestUrl(instance);
|
||||
log.info("拉取路由配置,serviceId: {}, url: {}", serviceName, url);
|
||||
ResponseEntity<String> responseEntity = getRestTemplate().getForEntity(url, String.class);
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
String body = responseEntity.getBody();
|
||||
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class);
|
||||
baseRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance));
|
||||
} else {
|
||||
log.error("拉取路由配置异常,url: {}, status: {}, body: {}", url, responseEntity.getStatusCodeValue(), responseEntity.getBody());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取路由请求url
|
||||
*
|
||||
* @param instance 服务实例
|
||||
* @return 返回最终url
|
||||
*/
|
||||
private static String getRouteRequestUrl(InstanceDefinition instance) {
|
||||
Map<String, String> metadata = instance.getMetadata();
|
||||
String customPath = metadata.get(METADATA_SOP_ROUTES_PATH);
|
||||
String homeUrl;
|
||||
String servletPath;
|
||||
// 如果metadata中指定了获取路由的url
|
||||
if (StringUtils.isNotBlank(customPath)) {
|
||||
// 自定义完整的url
|
||||
if (customPath.startsWith("http")) {
|
||||
homeUrl = customPath;
|
||||
servletPath = "";
|
||||
} else {
|
||||
homeUrl = getHomeUrl(instance);
|
||||
servletPath = customPath;
|
||||
}
|
||||
} else {
|
||||
// 默认处理
|
||||
homeUrl = getHomeUrl(instance);
|
||||
String contextPath = metadata.getOrDefault(METADATA_SERVER_CONTEXT_PATH, "");
|
||||
servletPath = contextPath + SOP_ROUTES_PATH;
|
||||
}
|
||||
if (StringUtils.isNotBlank(servletPath) && !servletPath.startsWith("/")) {
|
||||
servletPath = '/' + servletPath;
|
||||
}
|
||||
String query = buildQuery();
|
||||
return homeUrl + servletPath + query;
|
||||
}
|
||||
|
||||
private static String getHomeUrl(InstanceDefinition instance) {
|
||||
return "http://" + instance.getIp() + ":" + instance.getPort();
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package com.gitee.sop.gatewaycommon.validate;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.SopConstants;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class SignConfig {
|
||||
private static volatile Wrapper wrapper = new Wrapper() {};
|
||||
|
||||
public static void enableUrlencodeMode() {
|
||||
wrapper = new Wrapper() {
|
||||
@Override
|
||||
public String wrapVal(Object val) {
|
||||
String valStr = String.valueOf(val);
|
||||
try {
|
||||
return URLEncoder.encode(valStr, SopConstants.UTF8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return valStr;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static String wrapVal(Object val) {
|
||||
return wrapper.wrapVal(val);
|
||||
}
|
||||
|
||||
interface Wrapper {
|
||||
default String wrapVal(Object val) {
|
||||
return String.valueOf(val);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -5,6 +5,7 @@
|
||||
package com.gitee.sop.gatewaycommon.validate.alipay;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
|
||||
import com.gitee.sop.gatewaycommon.validate.SignConfig;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
@@ -188,13 +189,13 @@ public class AlipaySignature {
|
||||
params.remove("sign");
|
||||
params.remove("sign_type");
|
||||
|
||||
StringBuffer content = new StringBuffer();
|
||||
StringBuilder content = new StringBuilder();
|
||||
List<String> keys = new ArrayList<String>(params.keySet());
|
||||
Collections.sort(keys);
|
||||
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String key = keys.get(i);
|
||||
String value = params.get(key);
|
||||
String value = SignConfig.wrapVal(params.get(key));
|
||||
content.append((i == 0 ? "" : "&") + key + "=" + value);
|
||||
}
|
||||
|
||||
@@ -208,13 +209,13 @@ public class AlipaySignature {
|
||||
|
||||
params.remove("sign");
|
||||
|
||||
StringBuffer content = new StringBuffer();
|
||||
StringBuilder content = new StringBuilder();
|
||||
List<String> keys = new ArrayList<String>(params.keySet());
|
||||
Collections.sort(keys);
|
||||
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String key = keys.get(i);
|
||||
String value = String.valueOf(params.get(key));
|
||||
String value = SignConfig.wrapVal(params.get(key));
|
||||
content.append((i == 0 ? "" : "&") + key + "=" + value);
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ package com.gitee.sop.gatewaycommon.validate.taobao;
|
||||
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
|
||||
import com.gitee.sop.gatewaycommon.param.ApiParam;
|
||||
import com.gitee.sop.gatewaycommon.validate.AbstractSigner;
|
||||
import com.gitee.sop.gatewaycommon.validate.SignConfig;
|
||||
import com.gitee.sop.gatewaycommon.validate.SignEncipher;
|
||||
import com.gitee.sop.gatewaycommon.validate.SignEncipherHMAC_MD5;
|
||||
import com.gitee.sop.gatewaycommon.validate.SignEncipherMD5;
|
||||
@@ -47,8 +48,8 @@ public class TaobaoSigner extends AbstractSigner {
|
||||
// 第二步:把所有参数名和参数值串在一起
|
||||
StringBuilder paramNameValue = new StringBuilder();
|
||||
for (String paramName : paramNames) {
|
||||
Object val = param.get(paramName);
|
||||
if (val != null && StringUtils.isNotBlank(String.valueOf(val))) {
|
||||
String val = SignConfig.wrapVal(param.get(paramName));
|
||||
if (StringUtils.isNotBlank(val)) {
|
||||
paramNameValue.append(paramName).append(val);
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.4.RELEASE</version>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
@@ -16,13 +16,31 @@
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
|
||||
<version>0.9.0.RELEASE</version>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<artifactId>sop-gateway-common</artifactId>
|
||||
<version>2.1.3-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@@ -3,13 +3,23 @@ package com.gitee.sop.websiteserver.config;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.gitee.sop.gatewaycommon.route.EurekaRegistryListener;
|
||||
import com.gitee.sop.gatewaycommon.route.NacosRegistryListener;
|
||||
import com.gitee.sop.gatewaycommon.route.RegistryListener;
|
||||
import com.gitee.sop.gatewaycommon.route.ServiceListener;
|
||||
import com.gitee.sop.websiteserver.listener.ServiceDocListener;
|
||||
import com.gitee.sop.websiteserver.manager.DocManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.EventListener;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
@@ -20,6 +30,9 @@ public class WebsiteConfig implements ApplicationRunner {
|
||||
@Autowired
|
||||
DocManager docManager;
|
||||
|
||||
@Autowired
|
||||
private RegistryListener registryListener;
|
||||
|
||||
/**
|
||||
* 使用fastjson代替jackson
|
||||
* @return
|
||||
@@ -35,6 +48,37 @@ public class WebsiteConfig implements ApplicationRunner {
|
||||
return new HttpMessageConverters(converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* nacos事件监听
|
||||
*
|
||||
* @param heartbeatEvent
|
||||
*/
|
||||
@EventListener(classes = HeartbeatEvent.class)
|
||||
public void listenNacosEvent(ApplicationEvent heartbeatEvent) {
|
||||
registryListener.onEvent(heartbeatEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微服务路由加载
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty("spring.cloud.nacos.discovery.server-addr")
|
||||
RegistryListener registryListenerNacos() {
|
||||
return new NacosRegistryListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty("eureka.client.serviceUrl.defaultZone")
|
||||
RegistryListener registryListenerEureka() {
|
||||
return new EurekaRegistryListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ServiceListener serviceListener() {
|
||||
return new ServiceDocListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* SpringBoot启动完毕执行
|
||||
*/
|
||||
|
@@ -0,0 +1,50 @@
|
||||
package com.gitee.sop.websiteserver.listener;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.route.BaseServiceListener;
|
||||
import com.gitee.sop.websiteserver.manager.DocManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public class ServiceDocListener extends BaseServiceListener {
|
||||
|
||||
private static final String SECRET = "b749a2ec000f4f29";
|
||||
|
||||
@Autowired
|
||||
private DocManager docManager;
|
||||
|
||||
@Override
|
||||
public void onRemoveService(String serviceId) {
|
||||
docManager.remove(serviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddInstance(InstanceDefinition instance) {
|
||||
String serviceId = instance.getServiceId();
|
||||
String url = getRouteRequestUrl(instance);
|
||||
ResponseEntity<String> responseEntity = getRestTemplate().getForEntity(url, String.class);
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
String body = responseEntity.getBody();
|
||||
docManager.addDocInfo(
|
||||
serviceId
|
||||
, body
|
||||
, callback -> log.info("加载服务文档,serviceId={}, 机器={}"
|
||||
, serviceId
|
||||
, instance.getIp() + ":" + instance.getPort())
|
||||
);
|
||||
} else {
|
||||
log.error("加载文档失败, status:{}, body:{}", responseEntity.getStatusCodeValue(), responseEntity.getBody());
|
||||
}
|
||||
}
|
||||
|
||||
private static String getRouteRequestUrl(InstanceDefinition instance) {
|
||||
String query = buildQuery(SECRET);
|
||||
return "http://" + instance.getIp() + ":" + instance.getPort() + "/v2/api-docs" + query;
|
||||
}
|
||||
}
|
@@ -1,116 +0,0 @@
|
||||
package com.gitee.sop.websiteserver.manager;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.NamingService;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DocDiscovery {
|
||||
|
||||
private static final String SECRET = "b749a2ec000f4f29";
|
||||
|
||||
private static final int FIVE_SECONDS = 1000 * 5;
|
||||
|
||||
@Autowired
|
||||
private NacosDiscoveryProperties nacosDiscoveryProperties;
|
||||
|
||||
private RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
private Map<String, Long> updateTimeMap = new HashMap<>(16);
|
||||
|
||||
public DocDiscovery() {
|
||||
// 解决statusCode不等于200,就抛异常问题
|
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||
@Override
|
||||
protected boolean hasError(HttpStatus statusCode) {
|
||||
return statusCode == null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void refresh(DocManager docManager) {
|
||||
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||
List<ServiceInfo> subscribes = null;
|
||||
try {
|
||||
subscribes = namingService.getSubscribeServices();
|
||||
} catch (NacosException e) {
|
||||
log.error("namingService.getSubscribeServices()错误", e);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(subscribes)) {
|
||||
return;
|
||||
}
|
||||
// subscribe
|
||||
String thisServiceId = nacosDiscoveryProperties.getService();
|
||||
for (ServiceInfo serviceInfo : subscribes) {
|
||||
String serviceId = serviceInfo.getName();
|
||||
// 如果是本机服务,跳过
|
||||
if (Objects.equals(thisServiceId, serviceId) || "api-gateway".equalsIgnoreCase(serviceId)) {
|
||||
continue;
|
||||
}
|
||||
// nacos会不停的触发事件,这里做了一层拦截
|
||||
// 同一个serviceId5秒内允许访问一次
|
||||
Long lastUpdateTime = updateTimeMap.getOrDefault(serviceId, 0L);
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastUpdateTime < FIVE_SECONDS) {
|
||||
continue;
|
||||
}
|
||||
updateTimeMap.put(serviceId, now);
|
||||
try {
|
||||
List<Instance> allInstances = namingService.getAllInstances(serviceId);
|
||||
if (CollectionUtils.isEmpty(allInstances)) {
|
||||
// 如果没有服务列表,则删除所有路由信息
|
||||
docManager.remove(serviceId);
|
||||
} else {
|
||||
for (Instance instance : allInstances) {
|
||||
String url = getRouteRequestUrl(instance);
|
||||
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
String body = responseEntity.getBody();
|
||||
docManager.addDocInfo(
|
||||
serviceId
|
||||
, body
|
||||
, callback -> log.info("加载服务文档,serviceId={}, 机器={}"
|
||||
, serviceId, instance.getIp() + ":" + instance.getPort())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NacosException e) {
|
||||
log.error("选择服务实例失败,serviceId:{}", serviceId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getRouteRequestUrl(Instance instance) {
|
||||
String query = buildQuery(SECRET);
|
||||
return "http://" + instance.getIp() + ":" + instance.getPort() + "/v2/api-docs" + query;
|
||||
}
|
||||
|
||||
private static String buildQuery(String secret) {
|
||||
String time = String.valueOf(System.currentTimeMillis());
|
||||
String source = secret + time + secret;
|
||||
String sign = DigestUtils.md5DigestAsHex(source.getBytes());
|
||||
return "?time=" + time + "&sign=" + sign;
|
||||
}
|
||||
|
||||
}
|
@@ -5,9 +5,6 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.parser.Feature;
|
||||
import com.gitee.sop.websiteserver.bean.DocInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
@@ -23,7 +20,7 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DocManagerImpl implements DocManager, ApplicationListener<HeartbeatEvent> {
|
||||
public class DocManagerImpl implements DocManager {
|
||||
|
||||
// key:title
|
||||
private Map<String, DocInfo> docDefinitionMap = new HashMap<>();
|
||||
@@ -37,9 +34,6 @@ public class DocManagerImpl implements DocManager, ApplicationListener<Heartbeat
|
||||
|
||||
private DocParser easyopenDocParser = new EasyopenDocParser();
|
||||
|
||||
@Autowired
|
||||
private DocDiscovery docDiscovery;
|
||||
|
||||
@Override
|
||||
public void addDocInfo(String serviceId, String docInfoJson, Consumer<DocInfo> callback) {
|
||||
String newMd5 = DigestUtils.md5DigestAsHex(docInfoJson.getBytes(StandardCharsets.UTF_8));
|
||||
@@ -80,10 +74,4 @@ public class DocManagerImpl implements DocManager, ApplicationListener<Heartbeat
|
||||
serviceIdMd5Map.remove(serviceId);
|
||||
docDefinitionMap.entrySet().removeIf(entry -> serviceId.equalsIgnoreCase(entry.getValue().getServiceId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(HeartbeatEvent heartbeatEvent) {
|
||||
docDiscovery.refresh(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,12 +2,14 @@ server.port=8083
|
||||
spring.application.name=website-server
|
||||
|
||||
# ------- 需要改的配置 -------
|
||||
# nacos地址
|
||||
nacos.url=127.0.0.1:8848
|
||||
eureka.url=http://localhost:1111/eureka/
|
||||
# ------- 需要改的配置end -------
|
||||
|
||||
# nacos cloud配置
|
||||
spring.cloud.nacos.discovery.server-addr=${nacos.url}
|
||||
# eureka注册中心
|
||||
eureka.client.serviceUrl.defaultZone=${eureka.url}
|
||||
|
||||
## nacos cloud配置
|
||||
#spring.cloud.nacos.discovery.server-addr=${nacos.url}
|
||||
|
||||
# 测试环境
|
||||
api.url-test=http://open-test.yourdomain.com
|
||||
|
Reference in New Issue
Block a user