mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
3.2.0
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
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,53 +39,18 @@ public class NacosRegistryListener extends BaseRegistryListener {
|
||||
|
||||
@Override
|
||||
public synchronized void onEvent(ApplicationEvent applicationEvent) {
|
||||
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||
ListView<String> servicesOfServer = null;
|
||||
try {
|
||||
servicesOfServer = namingService.getServicesOfServer(1, Integer.MAX_VALUE);
|
||||
} catch (NacosException e) {
|
||||
log.error("namingService.getServicesOfServer()错误", e);
|
||||
}
|
||||
if (servicesOfServer == null || CollectionUtils.isEmpty(servicesOfServer.getData())) {
|
||||
return;
|
||||
}
|
||||
List<NacosServiceHolder> serviceList = this.getServiceList();
|
||||
final Set<NacosServiceHolder> currentServices = new HashSet<>(serviceList);
|
||||
|
||||
Map<String, Instance> instanceMap = 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()
|
||||
.orElse(null);
|
||||
return instance == null ? null : new InstanceInfo(serviceName, 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);
|
||||
currentServices.forEach(nacosServiceHolder -> {
|
||||
Instance instance = nacosServiceHolder.getInstance();
|
||||
InstanceDefinition instanceDefinition = new InstanceDefinition();
|
||||
instanceDefinition.setInstanceId(instance.getInstanceId());
|
||||
instanceDefinition.setServiceId(serviceName);
|
||||
instanceDefinition.setServiceId(nacosServiceHolder.getServiceId());
|
||||
instanceDefinition.setIp(instance.getIp());
|
||||
instanceDefinition.setPort(instance.getPort());
|
||||
instanceDefinition.setMetadata(instance.getMetadata());
|
||||
@@ -95,18 +61,63 @@ public class NacosRegistryListener extends BaseRegistryListener {
|
||||
});
|
||||
}
|
||||
|
||||
// 如果有服务删除
|
||||
Set<String> removedServiceIdList = getRemovedServiceId(serviceNames);
|
||||
if (removedServiceIdList.size() > 0) {
|
||||
removedServiceIdList.forEach(serviceId->{
|
||||
this.removeRoutes(serviceId);
|
||||
if (registryEventList != null) {
|
||||
registryEventList.forEach(registryEvent -> registryEvent.onRemove(serviceId));
|
||||
}
|
||||
});
|
||||
// 如果有服务下线
|
||||
Set<String> removedServiceIdList = getRemovedServiceId(serviceList);
|
||||
// 移除
|
||||
this.doRemove(removedServiceIdList);
|
||||
|
||||
cacheServices = new HashSet<>(serviceList);
|
||||
}
|
||||
|
||||
cacheServices = new HashSet<>(serviceNames);
|
||||
/**
|
||||
* 获取建康的服务实例
|
||||
* @return 没有返回空的list
|
||||
*/
|
||||
private List<NacosServiceHolder> getServiceList() {
|
||||
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||
ListView<String> servicesOfServer = null;
|
||||
try {
|
||||
servicesOfServer = namingService.getServicesOfServer(1, Integer.MAX_VALUE);
|
||||
} catch (NacosException e) {
|
||||
log.error("namingService.getServicesOfServer()错误", e);
|
||||
}
|
||||
if (servicesOfServer == null || CollectionUtils.isEmpty(servicesOfServer.getData())) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
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)
|
||||
// 根据启动时间倒叙,找到最新的服务器
|
||||
.max(Comparator.comparing(ins -> {
|
||||
String startupTime = ins.getMetadata().getOrDefault(METADATA_KEY_TIME_STARTUP, "0");
|
||||
return Long.valueOf(startupTime);
|
||||
}))
|
||||
.orElse(null);
|
||||
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.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容器加载完毕-----");
|
||||
|
Reference in New Issue
Block a user