mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
4.0.3
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public abstract class AbstractTargetRoute<T> implements TargetRoute<T> {
|
||||
|
||||
private ServiceRouteInfo serviceRouteInfo;
|
||||
private RouteDefinition routeDefinition;
|
||||
private T targetRoute;
|
||||
|
||||
public AbstractTargetRoute(ServiceRouteInfo serviceRouteInfo, RouteDefinition routeDefinition, T targetRoute) {
|
||||
this.serviceRouteInfo = serviceRouteInfo;
|
||||
this.routeDefinition = routeDefinition;
|
||||
this.targetRoute = targetRoute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceRouteInfo getServiceRouteInfo() {
|
||||
return serviceRouteInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouteDefinition getRouteDefinition() {
|
||||
return routeDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getTargetRouteDefinition() {
|
||||
return targetRoute;
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Data
|
||||
public class ServiceDefinition {
|
||||
|
||||
/**
|
||||
* 服务名称,对应spring.application.name
|
||||
*/
|
||||
private String serviceId;
|
||||
|
||||
public ServiceDefinition(String serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
}
|
||||
|
||||
public String fetchServiceIdLowerCase() {
|
||||
return serviceId.toLowerCase();
|
||||
}
|
||||
}
|
@@ -3,14 +3,14 @@ package com.gitee.sop.gatewaycommon.bean;
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface TargetRoute<T> {
|
||||
public interface TargetRoute {
|
||||
|
||||
/**
|
||||
* 返回服务信息
|
||||
*
|
||||
* @return 返回服务信息
|
||||
*/
|
||||
ServiceRouteInfo getServiceRouteInfo();
|
||||
ServiceDefinition getServiceDefinition();
|
||||
|
||||
/**
|
||||
* 返回微服务路由对象
|
||||
@@ -19,10 +19,4 @@ public interface TargetRoute<T> {
|
||||
*/
|
||||
RouteDefinition getRouteDefinition();
|
||||
|
||||
/**
|
||||
* 返回网关路由对象
|
||||
*
|
||||
* @return 返回网关路由对象
|
||||
*/
|
||||
T getTargetRouteDefinition();
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ public class EnvGrayFilter implements GlobalFilter, Ordered {
|
||||
if (targetRoute == null) {
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
String serviceId = targetRoute.getServiceRouteInfo().fetchServiceIdLowerCase();
|
||||
String serviceId = targetRoute.getServiceDefinition().fetchServiceIdLowerCase();
|
||||
// 如果服务在灰度阶段,返回一个灰度版本号
|
||||
String version = envGrayManager.getVersion(serviceId, nameVersion);
|
||||
if (version != null && envGrayManager.containsKey(serviceId, apiParam.fetchAppKey())) {
|
||||
|
@@ -1,46 +1,88 @@
|
||||
package com.gitee.sop.gatewaycommon.gateway.route;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.manager.BaseRouteCache;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteLoader;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepository;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.cloud.gateway.filter.FilterDefinition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class GatewayRouteCache extends BaseRouteCache<GatewayTargetRoute> {
|
||||
@Slf4j
|
||||
public class GatewayRouteCache implements RouteLoader {
|
||||
|
||||
/**
|
||||
* KEY:serviceId, value: md5
|
||||
*/
|
||||
private Map<String, String> serviceIdMd5Map = new HashMap<>();
|
||||
|
||||
private RouteRepository<GatewayTargetRoute> routeRepository;
|
||||
|
||||
public GatewayRouteCache(RouteRepository<GatewayTargetRoute> routeRepository) {
|
||||
super(routeRepository);
|
||||
this.routeRepository = routeRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GatewayTargetRoute buildTargetRoute(ServiceRouteInfo serviceRouteInfo, RouteDefinition routeDefinition) {
|
||||
org.springframework.cloud.gateway.route.RouteDefinition targetRoute = new org.springframework.cloud.gateway.route.RouteDefinition();
|
||||
targetRoute.setId(routeDefinition.getId());
|
||||
String path = routeDefinition.getPath();
|
||||
if (path != null && path.contains("{") && path.contains("}")) {
|
||||
path = path.replace('{', '?');
|
||||
path = path.replace('}', '?');
|
||||
public void load(ServiceRouteInfo serviceRouteInfo, Consumer<Object> callback) {
|
||||
try {
|
||||
String serviceId = serviceRouteInfo.getServiceId();
|
||||
String newMd5 = buildMd5(serviceRouteInfo.getRouteDefinitionList());
|
||||
String oldMd5 = serviceIdMd5Map.get(serviceId);
|
||||
if (Objects.equals(newMd5, oldMd5)) {
|
||||
return;
|
||||
}
|
||||
serviceIdMd5Map.put(serviceId, newMd5);
|
||||
|
||||
List<RouteDefinition> routeDefinitionList = serviceRouteInfo.getRouteDefinitionList();
|
||||
for (RouteDefinition routeDefinition : routeDefinitionList) {
|
||||
this.add(serviceId, routeDefinition);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("新增路由:{}", JSON.toJSONString(routeDefinition));
|
||||
}
|
||||
}
|
||||
this.routeRepository.refresh();
|
||||
callback.accept(null);
|
||||
} catch (Exception e) {
|
||||
log.error("加载路由信息失败,serviceRouteInfo:{}", serviceRouteInfo, e);
|
||||
}
|
||||
targetRoute.setUri(URI.create(routeDefinition.getUri() + "/" + path));
|
||||
targetRoute.setOrder(routeDefinition.getOrder());
|
||||
// 添加过滤器
|
||||
List<FilterDefinition> filterDefinitionList = routeDefinition.getFilters()
|
||||
.stream()
|
||||
.map(filter -> {
|
||||
FilterDefinition filterDefinition = new FilterDefinition();
|
||||
BeanUtils.copyProperties(filter, filterDefinition);
|
||||
return filterDefinition;
|
||||
})
|
||||
}
|
||||
|
||||
public void add(String serviceId, RouteDefinition routeDefinition) {
|
||||
GatewayTargetRoute targetRoute = new GatewayTargetRoute(new ServiceDefinition(serviceId), routeDefinition);
|
||||
routeRepository.add(targetRoute);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建路由id MD5
|
||||
*
|
||||
* @param routeDefinitionList 路由列表
|
||||
* @return 返回MD5
|
||||
*/
|
||||
private String buildMd5(List<RouteDefinition> routeDefinitionList) {
|
||||
List<String> routeIdList = routeDefinitionList.stream()
|
||||
.map(JSON::toJSONString)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
return new GatewayTargetRoute(serviceRouteInfo, routeDefinition, targetRoute);
|
||||
String md5Source = org.apache.commons.lang3.StringUtils.join(routeIdList, "");
|
||||
return DigestUtils.md5DigestAsHex(md5Source.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String serviceId) {
|
||||
serviceIdMd5Map.remove(serviceId);
|
||||
routeRepository.deleteAll(serviceId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,19 +1,15 @@
|
||||
package com.gitee.sop.gatewaycommon.gateway.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.AbstractTargetRoute;
|
||||
import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
|
||||
import org.springframework.cloud.gateway.route.Route;
|
||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -32,8 +28,6 @@ import static java.util.Collections.synchronizedMap;
|
||||
@Slf4j
|
||||
public class GatewayRouteRepository implements RouteRepository<GatewayTargetRoute>, RouteLocator {
|
||||
|
||||
private final PathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
private static final Map<String, GatewayTargetRoute> routes = synchronizedMap(new LinkedHashMap<>());
|
||||
|
||||
@Autowired
|
||||
@@ -56,7 +50,7 @@ public class GatewayRouteRepository implements RouteRepository<GatewayTargetRout
|
||||
RouteLocatorBuilder.Builder builder = routeLocatorBuilder.routes();
|
||||
List<RouteDefinition> routeDefinitionList = routes.values()
|
||||
.stream()
|
||||
.map(AbstractTargetRoute::getRouteDefinition)
|
||||
.map(GatewayTargetRoute::getRouteDefinition)
|
||||
.collect(Collectors.toList());
|
||||
routeDefinitionList.forEach(routeDefinition -> builder.route(routeDefinition.getId(),
|
||||
r -> r.path(routeDefinition.getPath())
|
||||
@@ -75,32 +69,7 @@ public class GatewayRouteRepository implements RouteRepository<GatewayTargetRout
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
GatewayTargetRoute gatewayTargetRoute = routes.get(id);
|
||||
if (gatewayTargetRoute != null) {
|
||||
return gatewayTargetRoute;
|
||||
}
|
||||
for (Map.Entry<String, GatewayTargetRoute> entry : routes.entrySet()) {
|
||||
// /food/get/?id?
|
||||
String pattern = entry.getKey();
|
||||
if (this.pathMatcher.match(pattern, id)) {
|
||||
return clone(id, entry.getValue());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private GatewayTargetRoute clone(String path, GatewayTargetRoute gatewayTargetRoute) {
|
||||
String prefix = "/" + gatewayTargetRoute.getServiceRouteInfo().getServiceId();
|
||||
if (path.startsWith(prefix)) {
|
||||
path = path.substring(prefix.length());
|
||||
}
|
||||
RouteDefinition routeDefinition = gatewayTargetRoute.getRouteDefinition();
|
||||
RouteDefinition newRouteDefinition = new RouteDefinition();
|
||||
BeanUtils.copyProperties(routeDefinition, newRouteDefinition);
|
||||
newRouteDefinition.setPath(path);
|
||||
return new GatewayTargetRoute(gatewayTargetRoute.getServiceRouteInfo()
|
||||
, newRouteDefinition
|
||||
, gatewayTargetRoute.getTargetRouteDefinition());
|
||||
return routes.get(id);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +105,7 @@ public class GatewayRouteRepository implements RouteRepository<GatewayTargetRout
|
||||
@Override
|
||||
public void deleteAll(String serviceId) {
|
||||
List<String> idList = routes.values().stream()
|
||||
.filter(zuulTargetRoute -> StringUtils.equalsIgnoreCase(serviceId, zuulTargetRoute.getServiceRouteInfo().getServiceId()))
|
||||
.filter(zuulTargetRoute -> StringUtils.equalsIgnoreCase(serviceId, zuulTargetRoute.getServiceDefinition().getServiceId()))
|
||||
.map(zuulTargetRoute -> zuulTargetRoute.getRouteDefinition().getId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@@ -1,15 +1,30 @@
|
||||
package com.gitee.sop.gatewaycommon.gateway.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.AbstractTargetRoute;
|
||||
import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class GatewayTargetRoute extends AbstractTargetRoute<org.springframework.cloud.gateway.route.RouteDefinition> {
|
||||
public class GatewayTargetRoute implements TargetRoute {
|
||||
|
||||
public GatewayTargetRoute(ServiceRouteInfo serviceRouteInfo, RouteDefinition routeDefinition, org.springframework.cloud.gateway.route.RouteDefinition targetRoute) {
|
||||
super(serviceRouteInfo, routeDefinition, targetRoute);
|
||||
private ServiceDefinition serviceDefinition;
|
||||
private RouteDefinition routeDefinition;
|
||||
|
||||
|
||||
public GatewayTargetRoute(ServiceDefinition serviceDefinition, RouteDefinition routeDefinition) {
|
||||
this.serviceDefinition = serviceDefinition;
|
||||
this.routeDefinition = routeDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceDefinition getServiceDefinition() {
|
||||
return serviceDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouteDefinition getRouteDefinition() {
|
||||
return routeDefinition;
|
||||
}
|
||||
}
|
||||
|
@@ -1,90 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.manager;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseRouteCache<T extends TargetRoute> implements RouteLoader {
|
||||
|
||||
/**
|
||||
* KEY:serviceId, value: md5
|
||||
*/
|
||||
private Map<String, String> serviceIdMd5Map = new HashMap<>();
|
||||
|
||||
private RouteRepository<T> routeRepository;
|
||||
|
||||
/**
|
||||
* 构建目标路由对象,zuul和gateway定义的路由对象
|
||||
*
|
||||
* @param serviceRouteInfo 路由服务对象
|
||||
* @param gatewayRouteDefinition 路由对象
|
||||
* @return 返回目标路由对象
|
||||
*/
|
||||
protected abstract T buildTargetRoute(ServiceRouteInfo serviceRouteInfo, RouteDefinition gatewayRouteDefinition);
|
||||
|
||||
public BaseRouteCache(RouteRepository<T> routeRepository) {
|
||||
this.routeRepository = routeRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(ServiceRouteInfo serviceRouteInfo, Consumer<Object> callback) {
|
||||
try {
|
||||
String serviceId = serviceRouteInfo.getServiceId();
|
||||
String newMd5 = buildMd5(serviceRouteInfo.getRouteDefinitionList());
|
||||
String oldMd5 = serviceIdMd5Map.get(serviceId);
|
||||
if (Objects.equals(newMd5, oldMd5)) {
|
||||
return;
|
||||
}
|
||||
serviceIdMd5Map.put(serviceId, newMd5);
|
||||
|
||||
List<RouteDefinition> routeDefinitionList = serviceRouteInfo.getRouteDefinitionList();
|
||||
for (RouteDefinition routeDefinition : routeDefinitionList) {
|
||||
T targetRoute = this.buildTargetRoute(serviceRouteInfo, routeDefinition);
|
||||
routeRepository.add(targetRoute);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("新增路由:{}", JSON.toJSONString(routeDefinition));
|
||||
}
|
||||
}
|
||||
this.routeRepository.refresh();
|
||||
callback.accept(null);
|
||||
} catch (Exception e) {
|
||||
log.error("加载路由信息失败,serviceRouteInfo:{}", serviceRouteInfo, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建路由id MD5
|
||||
*
|
||||
* @param routeDefinitionList 路由列表
|
||||
* @return 返回MD5
|
||||
*/
|
||||
private String buildMd5(List<RouteDefinition> routeDefinitionList) {
|
||||
List<String> routeIdList = routeDefinitionList.stream()
|
||||
.map(JSON::toJSONString)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
String md5Source = org.apache.commons.lang3.StringUtils.join(routeIdList, "");
|
||||
return DigestUtils.md5DigestAsHex(md5Source.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String serviceId) {
|
||||
serviceIdMd5Map.remove(serviceId);
|
||||
routeRepository.deleteAll(serviceId);
|
||||
}
|
||||
}
|
@@ -24,7 +24,7 @@ public abstract class BaseForwardChooser<T> implements ForwardChooser<T>, ApiPar
|
||||
ApiParam apiParam = getApiParam(t);
|
||||
String nameVersion = apiParam.fetchNameVersion();
|
||||
TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion);
|
||||
String serviceId = targetRoute.getServiceRouteInfo().fetchServiceIdLowerCase();
|
||||
String serviceId = targetRoute.getServiceDefinition().fetchServiceIdLowerCase();
|
||||
// 如果服务在灰度阶段,返回一个灰度版本号
|
||||
String grayVersion = envGrayManager.getVersion(serviceId, nameVersion);
|
||||
// 如果是灰度环境
|
||||
|
@@ -3,7 +3,7 @@ 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 com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -24,10 +24,8 @@ public class ServiceRouteListener extends BaseServiceListener {
|
||||
|
||||
private static final String METADATA_SOP_ROUTES_PATH = "sop.routes.path";
|
||||
|
||||
private static final String HEADER_RESTFUL = "restful";
|
||||
|
||||
@Autowired
|
||||
private BaseRouteCache<?> baseRouteCache;
|
||||
private GatewayRouteCache gatewayRouteCache;
|
||||
|
||||
@Autowired
|
||||
private RoutesProcessor routesProcessor;
|
||||
@@ -35,7 +33,7 @@ public class ServiceRouteListener extends BaseServiceListener {
|
||||
@Override
|
||||
public void onRemoveService(String serviceId) {
|
||||
log.info("服务下线,删除路由配置,serviceId: {}", serviceId);
|
||||
baseRouteCache.remove(serviceId);
|
||||
gatewayRouteCache.remove(serviceId);
|
||||
routesProcessor.removeAllRoutes(serviceId);
|
||||
}
|
||||
|
||||
@@ -48,7 +46,7 @@ public class ServiceRouteListener extends BaseServiceListener {
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
String body = responseEntity.getBody();
|
||||
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class);
|
||||
baseRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance));
|
||||
gatewayRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance));
|
||||
} else {
|
||||
log.error("拉取路由配置异常,url: {}, status: {}, body: {}", url, responseEntity.getStatusCodeValue(), responseEntity.getBody());
|
||||
}
|
||||
|
@@ -129,7 +129,7 @@ public class ApiValidator implements Validator {
|
||||
}
|
||||
|
||||
private void initFields(TargetRoute targetRoute, ApiParam apiParam) {
|
||||
apiParam.setServiceId(targetRoute.getServiceRouteInfo().getServiceId());
|
||||
apiParam.setServiceId(targetRoute.getServiceDefinition().getServiceId());
|
||||
boolean mergeResult;
|
||||
Boolean defaultSetting = ApiContext.getApiConfig().getMergeResult();
|
||||
if (defaultSetting != null) {
|
||||
|
@@ -7,5 +7,5 @@ import com.gitee.sop.gateway.entity.ConfigServiceRoute;
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface ConfigServiceRouteMapper extends CrudMapper<ConfigServiceRoute, Long> {
|
||||
public interface ConfigServiceRouteMapper extends CrudMapper<ConfigServiceRoute, String> {
|
||||
}
|
||||
|
Reference in New Issue
Block a user