pull/2/MERGE
tanghc 5 years ago
parent 3118f07bbc
commit 2d10d58935
  1. 21
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java
  2. 23
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java
  3. 132
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NacosRegistryListener.java
  4. 20
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NacosServiceHolder.java
  5. 21
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ServiceHolder.java
  6. 6
      sop-common/sop-service-common/pom.xml
  7. 15
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java

@ -32,6 +32,8 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
@ -44,7 +46,11 @@ import java.util.Objects;
public class IndexFilter implements WebFilter {
private static final String REST_PATH_PREFIX = "/rest";
private static final String SOP_PATH_PREFIX = "/sop";
/** 路径白名单 */
private static List<String> PATH_WHITE_LIST = Arrays.asList(
"/sop", "/actuator"
);
@Value("${sop.gateway-index-path:/}")
private String indexPath;
@ -59,8 +65,8 @@ public class IndexFilter implements WebFilter {
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
// SOP路径,直接放行
if (path.startsWith(SOP_PATH_PREFIX)) {
// 路径是否在白名单中,直接放行
if (this.isPathInWhiteList(path)) {
return chain.filter(exchange);
}
// 如果是restful请求,直接转发
@ -125,6 +131,15 @@ public class IndexFilter implements WebFilter {
}
}
private boolean isPathInWhiteList(String path) {
for (String whitePath : PATH_WHITE_LIST) {
if (path.startsWith(whitePath)) {
return true;
}
}
return false;
}
private void doValidate(ServerWebExchange exchange, ApiParam apiParam) {
try {
validator.validate(apiParam);

@ -5,6 +5,7 @@ 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.Autowired;
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
import org.springframework.context.ApplicationEvent;
@ -23,6 +24,9 @@ public class EurekaRegistryListener extends BaseRegistryListener {
private Set<ServiceHolder> cacheServices = new HashSet<>();
@Autowired(required = false)
private List<RegistryEvent> registryEventList;
@Override
public void onEvent(ApplicationEvent applicationEvent) {
Object source = applicationEvent.getSource();
@ -57,10 +61,8 @@ public class EurekaRegistryListener extends BaseRegistryListener {
}
Set<String> removedServiceIdList = getRemovedServiceId(serviceList);
// 如果有服务删除
if (removedServiceIdList.size() > 0) {
this.doRemove(removedServiceIdList);
}
// 如果有服务下线
this.doRemove(removedServiceIdList);
cacheServices = new HashSet<>(serviceList);
}
@ -106,12 +108,23 @@ public class EurekaRegistryListener extends BaseRegistryListener {
instanceDefinition.setPort(instanceInfo.getPort());
instanceDefinition.setMetadata(instanceInfo.getMetadata());
pullRoutes(instanceDefinition);
if (registryEventList != null) {
registryEventList.forEach(registryEvent -> registryEvent.onRegistry(instanceDefinition));
}
}
});
}
private void doRemove(Set<String> deletedServices) {
deletedServices.forEach(this::removeRoutes);
if (deletedServices == null) {
return;
}
deletedServices.forEach(serviceId -> {
this.removeRoutes(serviceId);
if (registryEventList != null) {
registryEventList.forEach(registryEvent -> registryEvent.onRemove(serviceId));
}
});
}
}

@ -6,16 +6,15 @@ import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.util.CollectionUtils;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@ -28,7 +27,9 @@ import java.util.stream.Collectors;
@Slf4j
public class NacosRegistryListener extends BaseRegistryListener {
private volatile Set<String> cacheServices = new HashSet<>();
private static final String METADATA_KEY_TIME_STARTUP = "time.startup";
private volatile Set<NacosServiceHolder> cacheServices = new HashSet<>();
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@ -38,6 +39,41 @@ public class NacosRegistryListener extends BaseRegistryListener {
@Override
public synchronized void onEvent(ApplicationEvent applicationEvent) {
List<NacosServiceHolder> serviceList = this.getServiceList();
final Set<NacosServiceHolder> currentServices = new HashSet<>(serviceList);
// 删除现有的,剩下的就是新服务
currentServices.removeAll(cacheServices);
// 如果有新的服务注册进来
if (currentServices.size() > 0) {
currentServices.forEach(nacosServiceHolder -> {
Instance instance = nacosServiceHolder.getInstance();
InstanceDefinition instanceDefinition = new InstanceDefinition();
instanceDefinition.setInstanceId(instance.getInstanceId());
instanceDefinition.setServiceId(nacosServiceHolder.getServiceId());
instanceDefinition.setIp(instance.getIp());
instanceDefinition.setPort(instance.getPort());
instanceDefinition.setMetadata(instance.getMetadata());
pullRoutes(instanceDefinition);
if (registryEventList != null) {
registryEventList.forEach(registryEvent -> registryEvent.onRegistry(instanceDefinition));
}
});
}
// 如果有服务下线
Set<String> removedServiceIdList = getRemovedServiceId(serviceList);
// 移除
this.doRemove(removedServiceIdList);
cacheServices = new HashSet<>(serviceList);
}
/**
* 获取建康的服务实例
* @return 没有返回空的list
*/
private List<NacosServiceHolder> getServiceList() {
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
ListView<String> servicesOfServer = null;
try {
@ -46,67 +82,42 @@ public class NacosRegistryListener extends BaseRegistryListener {
log.error("namingService.getServicesOfServer()错误", e);
}
if (servicesOfServer == null || CollectionUtils.isEmpty(servicesOfServer.getData())) {
return;
return Collections.emptyList();
}
Map<String, Instance> instanceMap = servicesOfServer
return servicesOfServer
.getData()
.stream()
.filter(this::canOperator)
.map(serviceName -> {
try {
// 获取服务实例
List<Instance> allInstances = namingService.getAllInstances(serviceName);
if (CollectionUtils.isEmpty(allInstances)) {
return null;
}
Instance instance = allInstances.stream()
// 只获取建康实例
.filter(Instance::isHealthy)
.findFirst()
// 根据启动时间倒叙,找到最新的服务器
.max(Comparator.comparing(ins -> {
String startupTime = ins.getMetadata().getOrDefault(METADATA_KEY_TIME_STARTUP, "0");
return Long.valueOf(startupTime);
}))
.orElse(null);
return instance == null ? null : new InstanceInfo(serviceName, instance);
if (instance == null) {
return null;
} else {
String startupTime = instance.getMetadata().getOrDefault("time.startup", "0");
long time = Long.parseLong(startupTime);
return new NacosServiceHolder(serviceName, time, instance);
}
} catch (NacosException e) {
log.error("namingService.getAllInstances(serviceName)错误,serviceName:{}", serviceName, e);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toMap(InstanceInfo::getServiceName, InstanceInfo::getInstance));
Set<String> serviceNames = instanceMap.keySet();
final Set<String> currentServices = new HashSet<>(serviceNames);
// 删除现有的,剩下的就是新服务
currentServices.removeAll(cacheServices);
// 如果有新的服务注册进来
if (currentServices.size() > 0) {
currentServices.forEach(serviceName -> {
Instance instance = instanceMap.get(serviceName);
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);
if (registryEventList != null) {
registryEventList.forEach(registryEvent -> registryEvent.onRegistry(instanceDefinition));
}
});
}
// 如果有服务删除
Set<String> removedServiceIdList = getRemovedServiceId(serviceNames);
if (removedServiceIdList.size() > 0) {
removedServiceIdList.forEach(serviceId->{
this.removeRoutes(serviceId);
if (registryEventList != null) {
registryEventList.forEach(registryEvent -> registryEvent.onRemove(serviceId));
}
});
}
cacheServices = new HashSet<>(serviceNames);
.collect(Collectors.toList());
}
/**
@ -115,18 +126,29 @@ public class NacosRegistryListener extends BaseRegistryListener {
* @param serviceList 最新的serviceId集合
* @return 返回已下线的serviceId
*/
private Set<String> getRemovedServiceId(Set<String> serviceList) {
Set<String> cache = cacheServices;
// 删除最新的,剩下就是已经删除的
cache.removeAll(serviceList);
private Set<String> getRemovedServiceId(List<NacosServiceHolder> serviceList) {
Set<String> cache = cacheServices.stream()
.map(NacosServiceHolder::getServiceId)
.collect(Collectors.toSet());
Set<String> newList = serviceList.stream()
.map(NacosServiceHolder::getServiceId)
.collect(Collectors.toSet());
cache.removeAll(newList);
return cache;
}
@Data
@AllArgsConstructor
private static class InstanceInfo {
private String serviceName;
private Instance instance;
private void doRemove(Set<String> deletedServices) {
if (deletedServices == null) {
return;
}
deletedServices.forEach(serviceId -> {
this.removeRoutes(serviceId);
if (registryEventList != null) {
registryEventList.forEach(registryEvent -> registryEvent.onRemove(serviceId));
}
});
}
}

@ -0,0 +1,20 @@
package com.gitee.sop.gatewaycommon.route;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author tanghc
*/
public class NacosServiceHolder extends ServiceHolder {
private Instance instance;
public NacosServiceHolder(String serviceId, long lastUpdatedTimestamp, Instance instance) {
super(serviceId, lastUpdatedTimestamp);
this.instance = instance;
}
public Instance getInstance() {
return instance;
}
}

@ -2,10 +2,29 @@ package com.gitee.sop.gatewaycommon.route;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
import java.util.Objects;
@Getter
@Setter
@AllArgsConstructor
public class ServiceHolder {
private String serviceId;
private long lastUpdatedTimestamp;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ServiceHolder that = (ServiceHolder) o;
return lastUpdatedTimestamp == that.lastUpdatedTimestamp &&
serviceId.equals(that.serviceId);
}
@Override
public int hashCode() {
return Objects.hash(serviceId, lastUpdatedTimestamp);
}
}

@ -42,6 +42,11 @@
</dependency>
<!-- optional -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
@ -97,6 +102,7 @@
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

@ -1,5 +1,7 @@
package com.gitee.sop.servercommon.configuration;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosWatch;
import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.interceptor.ServiceContextInterceptor;
import com.gitee.sop.servercommon.manager.EnvironmentContext;
@ -7,13 +9,16 @@ import com.gitee.sop.servercommon.manager.ServiceRouteController;
import com.gitee.sop.servercommon.mapping.ApiMappingHandlerMapping;
import com.gitee.sop.servercommon.message.ServiceErrorFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -21,6 +26,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.List;
/**
@ -84,6 +90,15 @@ public class BaseServiceConfiguration implements WebMvcConfigurer, WebMvcRegistr
return new ServiceRouteController();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty("spring.cloud.nacos.discovery.server-addr")
public NacosWatch nacosWatch(NacosDiscoveryProperties nacosDiscoveryProperties, ObjectProvider<TaskScheduler> taskScheduler) {
// 在元数据中新增启动时间,不能修改这个值,不然网关拉取接口会有问题
nacosDiscoveryProperties.getMetadata().put("time.startup", String.valueOf(System.currentTimeMillis()));
return new NacosWatch(nacosDiscoveryProperties, taskScheduler);
}
@PostConstruct
public final void after() {
log.info("-----spring容器加载完毕-----");

Loading…
Cancel
Save