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. 90
      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
*/
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> {
}

Loading…
Cancel
Save