pull/3/head
tanghc 4 years ago
parent 45ceebc34b
commit 7468ce3524
  1. 32
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/AbstractTargetRoute.java
  2. 26
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ServiceDefinition.java
  3. 10
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/TargetRoute.java
  4. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/EnvGrayFilter.java
  5. 92
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteCache.java
  6. 37
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteRepository.java
  7. 25
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayTargetRoute.java
  8. 90
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/BaseRouteCache.java
  9. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java
  10. 10
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ServiceRouteListener.java
  11. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java
  12. 2
      sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigServiceRouteMapper.java

@ -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 * @author tanghc
*/ */
public interface TargetRoute<T> { public interface TargetRoute {
/** /**
* 返回服务信息 * 返回服务信息
* *
* @return 返回服务信息 * @return 返回服务信息
*/ */
ServiceRouteInfo getServiceRouteInfo(); ServiceDefinition getServiceDefinition();
/** /**
* 返回微服务路由对象 * 返回微服务路由对象
@ -19,10 +19,4 @@ public interface TargetRoute<T> {
*/ */
RouteDefinition getRouteDefinition(); RouteDefinition getRouteDefinition();
/**
* 返回网关路由对象
*
* @return 返回网关路由对象
*/
T getTargetRouteDefinition();
} }

@ -32,7 +32,7 @@ public class EnvGrayFilter implements GlobalFilter, Ordered {
if (targetRoute == null) { if (targetRoute == null) {
return chain.filter(exchange); return chain.filter(exchange);
} }
String serviceId = targetRoute.getServiceRouteInfo().fetchServiceIdLowerCase(); String serviceId = targetRoute.getServiceDefinition().fetchServiceIdLowerCase();
// 如果服务在灰度阶段,返回一个灰度版本号 // 如果服务在灰度阶段,返回一个灰度版本号
String version = envGrayManager.getVersion(serviceId, nameVersion); String version = envGrayManager.getVersion(serviceId, nameVersion);
if (version != null && envGrayManager.containsKey(serviceId, apiParam.fetchAppKey())) { if (version != null && envGrayManager.containsKey(serviceId, apiParam.fetchAppKey())) {

@ -1,46 +1,88 @@
package com.gitee.sop.gatewaycommon.gateway.route; 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.RouteDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo; 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 com.gitee.sop.gatewaycommon.manager.RouteRepository;
import org.springframework.beans.BeanUtils; import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.FilterDefinition; 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.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* @author tanghc * @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) { public GatewayRouteCache(RouteRepository<GatewayTargetRoute> routeRepository) {
super(routeRepository); this.routeRepository = routeRepository;
} }
@Override @Override
protected GatewayTargetRoute buildTargetRoute(ServiceRouteInfo serviceRouteInfo, RouteDefinition routeDefinition) { public void load(ServiceRouteInfo serviceRouteInfo, Consumer<Object> callback) {
org.springframework.cloud.gateway.route.RouteDefinition targetRoute = new org.springframework.cloud.gateway.route.RouteDefinition(); try {
targetRoute.setId(routeDefinition.getId()); String serviceId = serviceRouteInfo.getServiceId();
String path = routeDefinition.getPath(); String newMd5 = buildMd5(serviceRouteInfo.getRouteDefinitionList());
if (path != null && path.contains("{") && path.contains("}")) { String oldMd5 = serviceIdMd5Map.get(serviceId);
path = path.replace('{', '?'); if (Objects.equals(newMd5, oldMd5)) {
path = path.replace('}', '?'); return;
} }
targetRoute.setUri(URI.create(routeDefinition.getUri() + "/" + path)); serviceIdMd5Map.put(serviceId, newMd5);
targetRoute.setOrder(routeDefinition.getOrder());
// 添加过滤器 List<RouteDefinition> routeDefinitionList = serviceRouteInfo.getRouteDefinitionList();
List<FilterDefinition> filterDefinitionList = routeDefinition.getFilters() for (RouteDefinition routeDefinition : routeDefinitionList) {
.stream() this.add(serviceId, routeDefinition);
.map(filter -> { if (log.isDebugEnabled()) {
FilterDefinition filterDefinition = new FilterDefinition(); log.debug("新增路由:{}", JSON.toJSONString(routeDefinition));
BeanUtils.copyProperties(filter, filterDefinition); }
return filterDefinition; }
}) this.routeRepository.refresh();
callback.accept(null);
} catch (Exception e) {
log.error("加载路由信息失败,serviceRouteInfo:{}", serviceRouteInfo, e);
}
}
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()); .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; 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.RouteDefinition;
import com.gitee.sop.gatewaycommon.manager.RouteRepository; import com.gitee.sop.gatewaycommon.manager.RouteRepository;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import java.util.Collection; import java.util.Collection;
@ -32,8 +28,6 @@ import static java.util.Collections.synchronizedMap;
@Slf4j @Slf4j
public class GatewayRouteRepository implements RouteRepository<GatewayTargetRoute>, RouteLocator { public class GatewayRouteRepository implements RouteRepository<GatewayTargetRoute>, RouteLocator {
private final PathMatcher pathMatcher = new AntPathMatcher();
private static final Map<String, GatewayTargetRoute> routes = synchronizedMap(new LinkedHashMap<>()); private static final Map<String, GatewayTargetRoute> routes = synchronizedMap(new LinkedHashMap<>());
@Autowired @Autowired
@ -56,7 +50,7 @@ public class GatewayRouteRepository implements RouteRepository<GatewayTargetRout
RouteLocatorBuilder.Builder builder = routeLocatorBuilder.routes(); RouteLocatorBuilder.Builder builder = routeLocatorBuilder.routes();
List<RouteDefinition> routeDefinitionList = routes.values() List<RouteDefinition> routeDefinitionList = routes.values()
.stream() .stream()
.map(AbstractTargetRoute::getRouteDefinition) .map(GatewayTargetRoute::getRouteDefinition)
.collect(Collectors.toList()); .collect(Collectors.toList());
routeDefinitionList.forEach(routeDefinition -> builder.route(routeDefinition.getId(), routeDefinitionList.forEach(routeDefinition -> builder.route(routeDefinition.getId(),
r -> r.path(routeDefinition.getPath()) r -> r.path(routeDefinition.getPath())
@ -75,32 +69,7 @@ public class GatewayRouteRepository implements RouteRepository<GatewayTargetRout
if (id == null) { if (id == null) {
return null; return null;
} }
GatewayTargetRoute gatewayTargetRoute = routes.get(id); return 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());
} }
@ -136,7 +105,7 @@ public class GatewayRouteRepository implements RouteRepository<GatewayTargetRout
@Override @Override
public void deleteAll(String serviceId) { public void deleteAll(String serviceId) {
List<String> idList = routes.values().stream() 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()) .map(zuulTargetRoute -> zuulTargetRoute.getRouteDefinition().getId())
.collect(Collectors.toList()); .collect(Collectors.toList());

@ -1,15 +1,30 @@
package com.gitee.sop.gatewaycommon.gateway.route; 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.RouteDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo; import com.gitee.sop.gatewaycommon.bean.ServiceDefinition;
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
/** /**
* @author tanghc * @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) { private ServiceDefinition serviceDefinition;
super(serviceRouteInfo, routeDefinition, targetRoute); 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); ApiParam apiParam = getApiParam(t);
String nameVersion = apiParam.fetchNameVersion(); String nameVersion = apiParam.fetchNameVersion();
TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion); TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion);
String serviceId = targetRoute.getServiceRouteInfo().fetchServiceIdLowerCase(); String serviceId = targetRoute.getServiceDefinition().fetchServiceIdLowerCase();
// 如果服务在灰度阶段,返回一个灰度版本号 // 如果服务在灰度阶段,返回一个灰度版本号
String grayVersion = envGrayManager.getVersion(serviceId, nameVersion); String grayVersion = envGrayManager.getVersion(serviceId, nameVersion);
// 如果是灰度环境 // 如果是灰度环境

@ -3,7 +3,7 @@ package com.gitee.sop.gatewaycommon.route;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition; import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo; 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 lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; 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 METADATA_SOP_ROUTES_PATH = "sop.routes.path";
private static final String HEADER_RESTFUL = "restful";
@Autowired @Autowired
private BaseRouteCache<?> baseRouteCache; private GatewayRouteCache gatewayRouteCache;
@Autowired @Autowired
private RoutesProcessor routesProcessor; private RoutesProcessor routesProcessor;
@ -35,7 +33,7 @@ public class ServiceRouteListener extends BaseServiceListener {
@Override @Override
public void onRemoveService(String serviceId) { public void onRemoveService(String serviceId) {
log.info("服务下线,删除路由配置,serviceId: {}", serviceId); log.info("服务下线,删除路由配置,serviceId: {}", serviceId);
baseRouteCache.remove(serviceId); gatewayRouteCache.remove(serviceId);
routesProcessor.removeAllRoutes(serviceId); routesProcessor.removeAllRoutes(serviceId);
} }
@ -48,7 +46,7 @@ public class ServiceRouteListener extends BaseServiceListener {
if (responseEntity.getStatusCode() == HttpStatus.OK) { if (responseEntity.getStatusCode() == HttpStatus.OK) {
String body = responseEntity.getBody(); String body = responseEntity.getBody();
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class); ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class);
baseRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance)); gatewayRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance));
} else { } else {
log.error("拉取路由配置异常,url: {}, status: {}, body: {}", url, responseEntity.getStatusCodeValue(), responseEntity.getBody()); 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) { private void initFields(TargetRoute targetRoute, ApiParam apiParam) {
apiParam.setServiceId(targetRoute.getServiceRouteInfo().getServiceId()); apiParam.setServiceId(targetRoute.getServiceDefinition().getServiceId());
boolean mergeResult; boolean mergeResult;
Boolean defaultSetting = ApiContext.getApiConfig().getMergeResult(); Boolean defaultSetting = ApiContext.getApiConfig().getMergeResult();
if (defaultSetting != null) { if (defaultSetting != null) {

@ -7,5 +7,5 @@ import com.gitee.sop.gateway.entity.ConfigServiceRoute;
/** /**
* @author tanghc * @author tanghc
*/ */
public interface ConfigServiceRouteMapper extends CrudMapper<ConfigServiceRoute, Long> { public interface ConfigServiceRouteMapper extends CrudMapper<ConfigServiceRoute, String> {
} }

Loading…
Cancel
Save