mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
适配eureka
This commit is contained in:
@@ -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-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-alibaba-nacos-discovery</artifactId>
|
||||
<version>0.9.0.RELEASE</version>
|
||||
<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