mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 12:56:28 +08:00
路由管理优化
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public abstract class AbstractTargetRoute<R extends BaseServiceRouteInfo, E extends BaseRouteDefinition, T> implements TargetRoute<R,E, T> {
|
||||
|
||||
private R serviceRouteInfo;
|
||||
private E routeDefinition;
|
||||
private T targetRoute;
|
||||
|
||||
public AbstractTargetRoute(R serviceRouteInfo, E routeDefinition, T targetRoute) {
|
||||
this.serviceRouteInfo = serviceRouteInfo;
|
||||
this.routeDefinition = routeDefinition;
|
||||
this.targetRoute = targetRoute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R getServiceRouteInfo() {
|
||||
return serviceRouteInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getRouteDefinition() {
|
||||
return routeDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getTargetRouteDefinition() {
|
||||
return targetRoute;
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -9,7 +10,6 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
public class BaseServiceRouteInfo<T extends BaseRouteDefinition> {
|
||||
private String appName;
|
||||
private String md5;
|
||||
private List<T> routeDefinitionList;
|
||||
private String serviceId;
|
||||
private List<T> routeDefinitionList = Collections.emptyList();
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Data
|
||||
public class ServiceApiInfo {
|
||||
private String md5;
|
||||
private String appName;
|
||||
private List<ApiMeta> apis;
|
||||
|
||||
@Data
|
||||
public static class ApiMeta {
|
||||
/** 接口名 */
|
||||
private String name;
|
||||
/** 请求path */
|
||||
private String path;
|
||||
/** 版本号 */
|
||||
private String version;
|
||||
|
||||
public String fetchNameVersion() {
|
||||
return name + version;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public abstract class ServiceRouteRepository<R, E> {
|
||||
/**
|
||||
* key:serviceId
|
||||
*/
|
||||
private Map<String, Set<E>> serviceRouteMap = new ConcurrentHashMap<>();
|
||||
|
||||
public abstract String getServiceId(R r);
|
||||
|
||||
public void saveRouteDefinition(R serviceRouteInfo, E definition) {
|
||||
String serverId = getServiceId(serviceRouteInfo);
|
||||
Set<E> routeDefinitionSet = serviceRouteMap.putIfAbsent(serverId, new HashSet<>(16));
|
||||
if (routeDefinitionSet == null) {
|
||||
routeDefinitionSet = serviceRouteMap.get(serverId);
|
||||
}
|
||||
routeDefinitionSet.add(definition);
|
||||
}
|
||||
|
||||
public synchronized void deleteAll(R serviceRouteInfo, Consumer<E> consumer) {
|
||||
String serverId = getServiceId(serviceRouteInfo);
|
||||
Set<E> definitionSet = serviceRouteMap.getOrDefault(serverId, Collections.emptySet());
|
||||
for (E routeDefinition : definitionSet) {
|
||||
consumer.accept(routeDefinition);
|
||||
}
|
||||
definitionSet.clear();
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface TargetRoute<R extends BaseServiceRouteInfo, E extends BaseRouteDefinition, T> {
|
||||
R getServiceRouteInfo();
|
||||
|
||||
E getRouteDefinition();
|
||||
|
||||
T getTargetRouteDefinition();
|
||||
}
|
@@ -9,6 +9,7 @@ import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteRepository;
|
||||
import com.gitee.sop.gatewaycommon.gateway.route.NameVersionRoutePredicateFactory;
|
||||
import com.gitee.sop.gatewaycommon.gateway.route.ReadBodyRoutePredicateFactory;
|
||||
import com.gitee.sop.gatewaycommon.gateway.route.GatewayZookeeperRouteManager;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
|
||||
import com.gitee.sop.gatewaycommon.message.ErrorFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -97,7 +98,9 @@ public class BaseGatewayConfiguration {
|
||||
|
||||
@Bean
|
||||
GatewayRouteRepository gatewayRouteRepository() {
|
||||
return new GatewayRouteRepository();
|
||||
GatewayRouteRepository gatewayRouteRepository = new GatewayRouteRepository();
|
||||
RouteRepositoryContext.setRouteRepository(gatewayRouteRepository);
|
||||
return gatewayRouteRepository;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,31 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.gateway.route;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class GatewayContext {
|
||||
|
||||
public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext";
|
||||
|
||||
/**
|
||||
* cache json body
|
||||
*/
|
||||
private String cacheBody;
|
||||
/**
|
||||
* cache formdata
|
||||
*/
|
||||
private MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
||||
/**
|
||||
* cache reqeust path
|
||||
*/
|
||||
private String path;
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
package com.gitee.sop.gatewaycommon.gateway.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteRepository;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -13,19 +12,23 @@ import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
|
||||
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
|
||||
import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
||||
import org.springframework.cloud.gateway.support.ConfigurationUtils;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.validation.Validator;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Collections.synchronizedMap;
|
||||
|
||||
/**
|
||||
* 路由存储管理,负责动态更新路由
|
||||
@@ -33,20 +36,15 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* @author thc
|
||||
*/
|
||||
@Slf4j
|
||||
public class GatewayRouteRepository extends InMemoryRouteDefinitionRepository
|
||||
implements ApplicationEventPublisherAware,
|
||||
public class GatewayRouteRepository implements ApplicationEventPublisherAware,
|
||||
RouteDefinitionRepository,
|
||||
BeanFactoryAware,
|
||||
RouteRepository<GatewayServiceRouteInfo, RouteDefinition> {
|
||||
RouteRepository<GatewayTargetRoute> {
|
||||
|
||||
private final Map<String, GatewayTargetRoute> routes = synchronizedMap(new LinkedHashMap<>());
|
||||
|
||||
private final SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
private ServiceRouteRepository<GatewayServiceRouteInfo, RouteDefinition> serviceRouteRepository = new ServiceRouteRepository<GatewayServiceRouteInfo, RouteDefinition>() {
|
||||
@Override
|
||||
public String getServiceId(GatewayServiceRouteInfo serviceRouteInfo) {
|
||||
return serviceRouteInfo.getAppName();
|
||||
}
|
||||
};
|
||||
|
||||
@Autowired
|
||||
private ConversionService conversionService;
|
||||
|
||||
@@ -57,31 +55,54 @@ public class GatewayRouteRepository extends InMemoryRouteDefinitionRepository
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public Flux<RouteDefinition> getRouteDefinitions() {
|
||||
List<RouteDefinition> list = routes.values().parallelStream()
|
||||
.map(targetRoute -> targetRoute.getTargetRouteDefinition())
|
||||
.collect(Collectors.toList());
|
||||
return Flux.fromIterable(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> save(Mono<RouteDefinition> route) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> delete(Mono<String> routeId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取路由
|
||||
*/
|
||||
@Override
|
||||
public RouteDefinition get(String id) {
|
||||
return getRouteDefinitions()
|
||||
.filter(routeDefinition -> {
|
||||
return routeDefinition.getId().equals(id);
|
||||
}).blockFirst();
|
||||
public GatewayTargetRoute get(String id) {
|
||||
return routes.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加路由
|
||||
*/
|
||||
@Override
|
||||
public String add(GatewayServiceRouteInfo serviceRouteInfo, RouteDefinition definition) {
|
||||
super.save(Mono.just(definition)).subscribe();
|
||||
serviceRouteRepository.saveRouteDefinition(serviceRouteInfo, definition);
|
||||
this.initPredicateDefinition(definition);
|
||||
public String add(GatewayTargetRoute targetRoute) {
|
||||
GatewayRouteDefinition baseRouteDefinition = targetRoute.getRouteDefinition();
|
||||
routes.put(baseRouteDefinition.getId(), targetRoute);
|
||||
this.initPredicateDefinition(targetRoute);
|
||||
this.publisher.publishEvent(new RefreshRoutesEvent(this));
|
||||
return "success";
|
||||
}
|
||||
|
||||
protected void initPredicateDefinition(RouteDefinition definition) {
|
||||
for (PredicateDefinition predicate : definition.getPredicates()) {
|
||||
@Override
|
||||
public void update(GatewayTargetRoute targetRoute) {
|
||||
GatewayRouteDefinition baseRouteDefinition = targetRoute.getRouteDefinition();
|
||||
routes.put(baseRouteDefinition.getId(), targetRoute);
|
||||
}
|
||||
|
||||
protected void initPredicateDefinition(GatewayTargetRoute targetRoute) {
|
||||
GatewayRouteDefinition routeDefinition = targetRoute.getRouteDefinition();
|
||||
RouteDefinition targetRouteDefinition = targetRoute.getTargetRouteDefinition();
|
||||
for (PredicateDefinition predicate : targetRouteDefinition.getPredicates()) {
|
||||
Map<String, String> args = predicate.getArgs();
|
||||
if (!args.isEmpty()) {
|
||||
RoutePredicateFactory<NameVersionRoutePredicateFactory.Config> factory = new NameVersionRoutePredicateFactory();
|
||||
@@ -89,7 +110,7 @@ public class GatewayRouteRepository extends InMemoryRouteDefinitionRepository
|
||||
Object config = factory.newConfig();
|
||||
ConfigurationUtils.bind(config, properties, factory.shortcutFieldPrefix(), predicate.getName(),
|
||||
validator, conversionService);
|
||||
this.publisher.publishEvent(new PredicateArgsEvent(this, definition.getId(), properties));
|
||||
this.publisher.publishEvent(new PredicateArgsEvent(this, routeDefinition.getId(), properties));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,15 +121,19 @@ public class GatewayRouteRepository extends InMemoryRouteDefinitionRepository
|
||||
*/
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
super.delete(Mono.just(id));
|
||||
routes.remove(id);
|
||||
this.publisher.publishEvent(new PredicateArgsEvent(this, id, Collections.emptyMap()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(GatewayServiceRouteInfo serviceRouteInfo) {
|
||||
serviceRouteRepository.deleteAll(serviceRouteInfo, routeDefinition -> {
|
||||
this.delete(routeDefinition.getId());
|
||||
});
|
||||
public void deleteAll(String serviceId) {
|
||||
List<String> idList = this.routes.values().stream()
|
||||
.map(zuulTargetRoute -> zuulTargetRoute.getRouteDefinition().getId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (String id : idList) {
|
||||
this.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,13 @@
|
||||
package com.gitee.sop.gatewaycommon.gateway.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.AbstractTargetRoute;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class GatewayTargetRoute extends AbstractTargetRoute<GatewayServiceRouteInfo, GatewayRouteDefinition, RouteDefinition> {
|
||||
public GatewayTargetRoute(GatewayServiceRouteInfo baseServiceRouteInfo, GatewayRouteDefinition baseRouteDefinition, RouteDefinition targetRoute) {
|
||||
super(baseServiceRouteInfo, baseRouteDefinition, targetRoute);
|
||||
}
|
||||
}
|
@@ -21,9 +21,9 @@ import java.util.List;
|
||||
*/
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class GatewayZookeeperRouteManager extends BaseRouteManager<GatewayServiceRouteInfo, GatewayRouteDefinition, RouteDefinition> {
|
||||
public class GatewayZookeeperRouteManager extends BaseRouteManager<GatewayServiceRouteInfo, GatewayRouteDefinition, GatewayTargetRoute> {
|
||||
|
||||
public GatewayZookeeperRouteManager(Environment environment, RouteRepository<GatewayServiceRouteInfo, RouteDefinition> routeRepository) {
|
||||
public GatewayZookeeperRouteManager(Environment environment, RouteRepository<GatewayTargetRoute> routeRepository) {
|
||||
super(environment, routeRepository);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,12 @@ public class GatewayZookeeperRouteManager extends BaseRouteManager<GatewayServic
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RouteDefinition buildRouteDefinition(GatewayServiceRouteInfo serviceRouteInfo,GatewayRouteDefinition gatewayRouteDefinition) {
|
||||
protected Class<GatewayRouteDefinition> getRouteDefinitionClass() {
|
||||
return GatewayRouteDefinition.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GatewayTargetRoute buildRouteDefinition(GatewayServiceRouteInfo serviceRouteInfo, GatewayRouteDefinition gatewayRouteDefinition) {
|
||||
RouteDefinition routeDefinition = new RouteDefinition();
|
||||
routeDefinition.setId(gatewayRouteDefinition.getId());
|
||||
routeDefinition.setUri(URI.create(gatewayRouteDefinition.getUri()));
|
||||
@@ -54,7 +59,7 @@ public class GatewayZookeeperRouteManager extends BaseRouteManager<GatewayServic
|
||||
|
||||
routeDefinition.setFilters(filterDefinitionList);
|
||||
routeDefinition.setPredicates(predicateDefinitionList);
|
||||
return routeDefinition;
|
||||
return new GatewayTargetRoute(serviceRouteInfo, gatewayRouteDefinition, routeDefinition);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package com.gitee.sop.gatewaycommon.manager;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.sop.gatewaycommon.bean.BaseRouteDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.BaseServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||
@@ -20,7 +21,14 @@ import static com.gitee.sop.gatewaycommon.bean.SopConstants.SOP_SERVICE_ROUTE_PA
|
||||
|
||||
|
||||
/**
|
||||
* 路由管理
|
||||
* 路由管理,采用zookeeper实现,监听路由的增删改,并适时更新到本地。路由的存储格式为:
|
||||
* <pre>
|
||||
* /sop-service-route 根节点
|
||||
* /serviceId 服务节点,名字为服务名
|
||||
* /route1 路由节点,名字为:name+version,存放路由信息
|
||||
* /route2
|
||||
* /...
|
||||
* </pre>
|
||||
*
|
||||
* @param <R> 路由根对象,可以理解为最外面的大json:{....,routeDefinitionList:[]}
|
||||
* @param <E> 路由Item对象,对应大json里面的具体路由信息,routeDefinitionList:[]
|
||||
@@ -28,19 +36,38 @@ import static com.gitee.sop.gatewaycommon.bean.SopConstants.SOP_SERVICE_ROUTE_PA
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E extends BaseRouteDefinition, T> implements RouteManager {
|
||||
public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E extends BaseRouteDefinition, T extends TargetRoute> implements RouteManager {
|
||||
|
||||
protected String sopServiceApiPath = SOP_SERVICE_ROUTE_PATH;
|
||||
protected String sopRouteRootPath = SOP_SERVICE_ROUTE_PATH;
|
||||
|
||||
protected Environment environment;
|
||||
|
||||
protected RouteRepository<R, T> routeRepository;
|
||||
protected RouteRepository<T> routeRepository;
|
||||
|
||||
/**
|
||||
* 返回路由根对象class
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract Class<R> getServiceRouteInfoClass();
|
||||
|
||||
/**
|
||||
* 返回路由Item对象class
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract Class<E> getRouteDefinitionClass();
|
||||
|
||||
/**
|
||||
* 构建目标路由对象,zuul和gateway定义的路由对象
|
||||
*
|
||||
* @param serviceRouteInfo
|
||||
* @param routeDefinition
|
||||
* @return
|
||||
*/
|
||||
protected abstract T buildRouteDefinition(R serviceRouteInfo, E routeDefinition);
|
||||
|
||||
public BaseRouteManager(Environment environment, RouteRepository<R, T> routeRepository) {
|
||||
public BaseRouteManager(Environment environment, RouteRepository<T> routeRepository) {
|
||||
this.environment = environment;
|
||||
this.routeRepository = routeRepository;
|
||||
}
|
||||
@@ -65,18 +92,25 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
|
||||
.orSetData()
|
||||
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
|
||||
.creatingParentContainersIfNeeded()
|
||||
.forPath(sopServiceApiPath, "".getBytes());
|
||||
.forPath(sopRouteRootPath, "".getBytes());
|
||||
|
||||
this.watchChildren(client, sopServiceApiPath);
|
||||
this.watchServiceChange(client, sopRouteRootPath);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void watchChildren(CuratorFramework client, String sopServiceApiPath) throws Exception {
|
||||
/**
|
||||
* 监听微服务更改
|
||||
*
|
||||
* @param client
|
||||
* @param sopServiceApiPath
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void watchServiceChange(CuratorFramework client, String sopServiceApiPath) throws Exception {
|
||||
// 为子节点添加watcher
|
||||
// PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件
|
||||
final PathChildrenCache childrenCache = new PathChildrenCache(client, sopServiceApiPath, true);
|
||||
PathChildrenCache childrenCache = new PathChildrenCache(client, sopServiceApiPath, true);
|
||||
|
||||
/**
|
||||
* StartMode: 初始化方式
|
||||
@@ -88,17 +122,19 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
|
||||
|
||||
// 列出子节点数据列表,需要使用BUILD_INITIAL_CACHE同步初始化模式才能获得,异步是获取不到的
|
||||
List<ChildData> childDataList = childrenCache.getCurrentData();
|
||||
log.info("微服务API详细数据列表:");
|
||||
log.info("获取service列表:");
|
||||
for (ChildData childData : childDataList) {
|
||||
String nodeData = new String(childData.getData());
|
||||
log.info("\t* 子节点路径:" + childData.getPath() + ",该节点的数据为:" + nodeData);
|
||||
R serviceRouteInfo = JSON.parseObject(nodeData, getServiceRouteInfoClass());
|
||||
saveRouteDefinitionList(serviceRouteInfo);
|
||||
String serviceNodeData = new String(childData.getData());
|
||||
R serviceRouteInfo = JSON.parseObject(serviceNodeData, getServiceRouteInfoClass());
|
||||
String servicePath = childData.getPath();
|
||||
log.info("\t* service节点路径:" + servicePath + ",该节点的数据为:" + serviceNodeData);
|
||||
this.loadServiceRouteItem(client, serviceRouteInfo, servicePath);
|
||||
}
|
||||
// 添加事件监听器
|
||||
log.info("监听服务节点增删改,rootPath:{}", sopRouteRootPath);
|
||||
// 监听根节点下面的子节点
|
||||
childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
|
||||
@Override
|
||||
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
|
||||
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
|
||||
PathChildrenCacheEvent.Type type = event.getType();
|
||||
synchronized (type) {
|
||||
// 通过判断event type的方式来实现不同事件的触发
|
||||
@@ -106,41 +142,111 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
|
||||
String nodeData = new String(event.getData().getData());
|
||||
R serviceRouteInfo = JSON.parseObject(nodeData, getServiceRouteInfoClass());
|
||||
// 添加子节点时触发
|
||||
log.info("子节点:{}添加,数据为:{}", event.getData().getPath(), nodeData);
|
||||
saveRouteDefinitionList(serviceRouteInfo);
|
||||
String servicePath = event.getData().getPath();
|
||||
log.info("新增serviceId节点:{},数据为:{}", servicePath, nodeData);
|
||||
loadServiceRouteItem(client, serviceRouteInfo, servicePath);
|
||||
} else if (PathChildrenCacheEvent.Type.CHILD_UPDATED.equals(type)) {
|
||||
// 修改子节点数据时触发,暂时没有什么操作
|
||||
String nodeData = new String(event.getData().getData());
|
||||
R serviceRouteInfo = JSON.parseObject(nodeData, getServiceRouteInfoClass());
|
||||
// 修改子节点数据时触发
|
||||
log.info("子节点:{}修改,数据为:{}", event.getData().getPath(), nodeData);
|
||||
// 删除下面所有节点
|
||||
routeRepository.deleteAll(serviceRouteInfo);
|
||||
// 添加新节点
|
||||
saveRouteDefinitionList(serviceRouteInfo);
|
||||
log.info("修改serviceId节点:{},数据为:{}", event.getData().getPath(), nodeData);
|
||||
} else if (PathChildrenCacheEvent.Type.CHILD_REMOVED.equals(type)) {
|
||||
// 删除service节点
|
||||
String nodeData = new String(event.getData().getData());
|
||||
log.info("子节点:{}删除,数据为:{}", event.getData().getPath(), nodeData);
|
||||
log.info("删除serviceId节点:{},数据为:{}", event.getData().getPath(), nodeData);
|
||||
R serviceRouteInfo = JSON.parseObject(nodeData, getServiceRouteInfoClass());
|
||||
deleteRouteDefinitionList(serviceRouteInfo);
|
||||
routeRepository.deleteAll(serviceRouteInfo.getServiceId());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void saveRouteDefinitionList(R serviceRouteInfo) {
|
||||
for (E routeDefinitionItem : serviceRouteInfo.getRouteDefinitionList()) {
|
||||
RouteDefinitionItemContext.add(routeDefinitionItem);
|
||||
T routeDefinition = buildRouteDefinition(serviceRouteInfo, routeDefinitionItem);
|
||||
routeRepository.add(serviceRouteInfo, routeDefinition);
|
||||
/**
|
||||
* 加载service下的路由信息
|
||||
*
|
||||
* @param servicePath
|
||||
*/
|
||||
protected void loadServiceRouteItem(CuratorFramework client, R serviceRouteInfo, String servicePath) throws Exception {
|
||||
// 获取service节点下所有的路由节点,里面保存的是路由名称,前面没有斜杠"/"
|
||||
List<String> pathNameList = client.getChildren().forPath(servicePath);
|
||||
for (String pathName : pathNameList) {
|
||||
// 完整的路径
|
||||
String routeItemPath = servicePath + "/" + pathName;
|
||||
byte[] routeItemData = client.getData().forPath(routeItemPath);
|
||||
String routeDataJson = buildZookeeperData(routeItemData);
|
||||
log.info("加载路由,path:{}, 数据为:{}", routeItemPath, routeDataJson);
|
||||
this.saveRouteItem(serviceRouteInfo, routeDataJson);
|
||||
}
|
||||
this.watchRouteItems(client, serviceRouteInfo, servicePath);
|
||||
}
|
||||
|
||||
protected void deleteRouteDefinitionList(R serviceRouteInfo) {
|
||||
for (E routeDefinitionItem : serviceRouteInfo.getRouteDefinitionList()) {
|
||||
RouteDefinitionItemContext.delete(routeDefinitionItem);
|
||||
/**
|
||||
* 监听serviceId目录下面的子节点
|
||||
*
|
||||
* @param client
|
||||
* @param serviceRouteInfo
|
||||
* @param servicePath serviceId节点
|
||||
*/
|
||||
protected void watchRouteItems(CuratorFramework client, R serviceRouteInfo, String servicePath) throws Exception {
|
||||
log.info("监听路由节点增删改,servicePath:{}", servicePath);
|
||||
PathChildrenCache childrenCache = new PathChildrenCache(client, servicePath, true);
|
||||
childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
|
||||
// 添加事件监听器
|
||||
childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
|
||||
@Override
|
||||
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
|
||||
PathChildrenCacheEvent.Type type = event.getType();
|
||||
synchronized (type) {
|
||||
// 通过判断event type的方式来实现不同事件的触发
|
||||
if (PathChildrenCacheEvent.Type.CHILD_ADDED.equals(type)) {
|
||||
// 新增单个路由
|
||||
String routeDataJson = buildZookeeperData(event.getData().getData());
|
||||
log.info("新增单个路由,serviceId:{}, route:{}", serviceRouteInfo.getServiceId(), routeDataJson);
|
||||
saveRouteItem(serviceRouteInfo, routeDataJson);
|
||||
} else if (PathChildrenCacheEvent.Type.CHILD_UPDATED.equals(type)) {
|
||||
// 修改单个路由
|
||||
String routeDataJson = buildZookeeperData(event.getData().getData());
|
||||
log.info("修改单个路由,serviceId:{}, route:{}", serviceRouteInfo.getServiceId(), routeDataJson);
|
||||
updateRouteItem(serviceRouteInfo, routeDataJson);
|
||||
} else if (PathChildrenCacheEvent.Type.CHILD_REMOVED.equals(type)) {
|
||||
// 删除单个路由
|
||||
String routeDataJson = buildZookeeperData(event.getData().getData());
|
||||
log.info("删除单个路由,serviceId:{}, route:{}", serviceRouteInfo.getServiceId(), routeDataJson);
|
||||
deleteRouteItem(serviceRouteInfo, routeDataJson);
|
||||
}
|
||||
routeRepository.deleteAll(serviceRouteInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected void saveRouteItem(R serviceRouteInfo, String nodeDataJson) {
|
||||
T routeDefinition = getRouteDefinition(serviceRouteInfo, nodeDataJson);
|
||||
routeRepository.add(routeDefinition);
|
||||
}
|
||||
|
||||
protected void updateRouteItem(R serviceRouteInfo, String nodeDataJson) {
|
||||
T routeDefinition = getRouteDefinition(serviceRouteInfo, nodeDataJson);
|
||||
routeRepository.update(routeDefinition);
|
||||
}
|
||||
|
||||
protected void deleteRouteItem(R serviceRouteInfo, String nodeDataJson) {
|
||||
E routeDefinitionItem = getRouteDefinitionItem(nodeDataJson);
|
||||
routeRepository.delete(routeDefinitionItem.getId());
|
||||
}
|
||||
|
||||
protected T getRouteDefinition(R serviceRouteInfo, String nodeDataJson) {
|
||||
E routeDefinitionItem = getRouteDefinitionItem(nodeDataJson);
|
||||
T routeDefinition = buildRouteDefinition(serviceRouteInfo, routeDefinitionItem);
|
||||
return routeDefinition;
|
||||
}
|
||||
|
||||
protected E getRouteDefinitionItem(String nodeDataJson) {
|
||||
return JSON.parseObject(nodeDataJson, getRouteDefinitionClass());
|
||||
}
|
||||
|
||||
protected String buildZookeeperData(byte[] data) {
|
||||
return new String(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,27 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.manager;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.BaseRouteDefinition;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class RouteDefinitionItemContext {
|
||||
// key:id
|
||||
private static Map<String, BaseRouteDefinition> routeDefinitionMap = new HashMap<>(64);
|
||||
|
||||
public static void add(BaseRouteDefinition routeDefinition) {
|
||||
routeDefinitionMap.put(routeDefinition.getId(), routeDefinition);
|
||||
}
|
||||
|
||||
public static BaseRouteDefinition getRouteDefinition(String id) {
|
||||
return routeDefinitionMap.get(id);
|
||||
}
|
||||
|
||||
public static void delete(BaseRouteDefinition routeDefinition) {
|
||||
routeDefinitionMap.remove(routeDefinition.getId());
|
||||
}
|
||||
|
||||
}
|
@@ -6,8 +6,6 @@ package com.gitee.sop.gatewaycommon.manager;
|
||||
*/
|
||||
public interface RouteManager {
|
||||
|
||||
String API_STORE_KEY = "com.gitee.sop.api";
|
||||
|
||||
/**
|
||||
* 刷新素有的微服务接口信息
|
||||
*/
|
||||
|
@@ -1,14 +1,40 @@
|
||||
package com.gitee.sop.gatewaycommon.manager;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface RouteRepository<R, T> {
|
||||
public interface RouteRepository<T extends TargetRoute> {
|
||||
/**
|
||||
* 获取路由信息
|
||||
* @param id 路由id
|
||||
* @return
|
||||
*/
|
||||
T get(String id);
|
||||
|
||||
String add(R serviceRouteInfo, T route);
|
||||
/**
|
||||
* 添加路由
|
||||
* @param targetRoute
|
||||
* @return
|
||||
*/
|
||||
String add(T targetRoute);
|
||||
|
||||
/**
|
||||
* 更新路由
|
||||
* @param targetRoute
|
||||
*/
|
||||
void update(T targetRoute);
|
||||
|
||||
/**
|
||||
* 删除路由
|
||||
* @param id 路由id
|
||||
*/
|
||||
void delete(String id);
|
||||
|
||||
void deleteAll(R serviceRouteInfo);
|
||||
/**
|
||||
* 删除service下的所有路由
|
||||
* @param serviceId
|
||||
*/
|
||||
void deleteAll(String serviceId);
|
||||
}
|
||||
|
@@ -0,0 +1,19 @@
|
||||
package com.gitee.sop.gatewaycommon.manager;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class RouteRepositoryContext {
|
||||
private static RouteRepository<? extends TargetRoute> routeRepository;
|
||||
|
||||
public static RouteRepository<? extends TargetRoute> getRouteRepository() {
|
||||
return routeRepository;
|
||||
}
|
||||
|
||||
public static <T extends TargetRoute> void setRouteRepository(RouteRepository<T> routeRepository) {
|
||||
RouteRepositoryContext.routeRepository = routeRepository;
|
||||
}
|
||||
|
||||
}
|
@@ -1,21 +1,32 @@
|
||||
package com.gitee.sop.gatewaycommon.param;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.BaseRouteDefinition;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteDefinitionItemContext;
|
||||
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepository;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
|
||||
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public class ApiParamFactory {
|
||||
public static ApiParam build(Map<String, ?> params) {
|
||||
ApiParam apiParam = new ApiParam();
|
||||
for (Map.Entry<String, ?> entry : params.entrySet()) {
|
||||
apiParam.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BaseRouteDefinition routeDefinition = RouteDefinitionItemContext.getRouteDefinition(apiParam.fetchNameVersion());
|
||||
|
||||
RouteRepository<? extends TargetRoute> routeRepository = RouteRepositoryContext.getRouteRepository();
|
||||
if (routeRepository == null) {
|
||||
log.error("RouteRepositoryContext.setRouteRepository()方法未使用");
|
||||
throw ErrorEnum.AOP_UNKNOW_ERROR.getErrorMeta().getException();
|
||||
}
|
||||
TargetRoute targetRoute = routeRepository.get(apiParam.fetchNameVersion());
|
||||
BaseRouteDefinition routeDefinition = targetRoute.getRouteDefinition();
|
||||
if (routeDefinition == null) {
|
||||
throw ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getException();
|
||||
}
|
||||
|
@@ -1,13 +1,17 @@
|
||||
package com.gitee.sop.gatewaycommon.zuul.configuration;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.ApiContext;
|
||||
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteManager;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepository;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
|
||||
import com.gitee.sop.gatewaycommon.message.ErrorFactory;
|
||||
import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter;
|
||||
import com.gitee.sop.gatewaycommon.zuul.filter.PostResultFilter;
|
||||
import com.gitee.sop.gatewaycommon.zuul.filter.PreValidateFilter;
|
||||
import com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator;
|
||||
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteRepository;
|
||||
import com.gitee.sop.gatewaycommon.zuul.route.ZuulTargetRoute;
|
||||
import com.gitee.sop.gatewaycommon.zuul.route.ZuulZookeeperRouteManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
@@ -42,7 +46,9 @@ public class BaseZuulConfiguration {
|
||||
*/
|
||||
@Bean
|
||||
ZuulRouteRepository zuulRouteRepository() {
|
||||
return new ZuulRouteRepository();
|
||||
ZuulRouteRepository zuulRouteRepository = new ZuulRouteRepository();
|
||||
RouteRepositoryContext.setRouteRepository(zuulRouteRepository);
|
||||
return zuulRouteRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -87,7 +87,7 @@ public abstract class BaseZuulFilter extends ZuulFilter {
|
||||
|
||||
/**
|
||||
* to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
|
||||
* "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
|
||||
* "routeDefinition" for routing to an origin, "post" for post-routing filters, "error" for error handling.
|
||||
* We also support a "static" type for static responses see StaticResponseFilter.
|
||||
* Any filterType made be created or added and doRun by calling FilterProcessor.runFilters(type)
|
||||
*/
|
||||
@@ -95,7 +95,7 @@ public abstract class BaseZuulFilter extends ZuulFilter {
|
||||
/** zuul过滤器pre类型 */
|
||||
PRE("pre"),
|
||||
/** zuul过滤器route类型 */
|
||||
ROUTE("route"),
|
||||
ROUTE("routeDefinition"),
|
||||
/** zuul过滤器post类型 */
|
||||
POST("post"),
|
||||
/** zuul过滤器error类型 */
|
||||
|
@@ -2,19 +2,14 @@ package com.gitee.sop.gatewaycommon.zuul.filter;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.ApiContext;
|
||||
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
|
||||
import com.gitee.sop.gatewaycommon.bean.BaseRouteDefinition;
|
||||
import com.gitee.sop.gatewaycommon.exception.ApiException;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteDefinitionItemContext;
|
||||
import com.gitee.sop.gatewaycommon.param.ApiParam;
|
||||
import com.gitee.sop.gatewaycommon.validate.Validator;
|
||||
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
|
||||
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteDefinition;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import com.netflix.zuul.exception.ZuulException;
|
||||
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 前置校验
|
||||
* @author tanghc
|
||||
|
@@ -9,6 +9,7 @@ import org.springframework.core.Ordered;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 路由定位
|
||||
@@ -29,7 +30,10 @@ public class SopRouteLocator implements RouteLocator, Ordered {
|
||||
|
||||
@Override
|
||||
public List<Route> getRoutes() {
|
||||
return zuulRouteRepository.listAll();
|
||||
return zuulRouteRepository.listAll()
|
||||
.parallelStream()
|
||||
.map(zuulTargetRoute -> zuulTargetRoute.getTargetRouteDefinition())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +45,11 @@ public class SopRouteLocator implements RouteLocator, Ordered {
|
||||
public Route getMatchingRoute(String path) {
|
||||
ApiParam param = ZuulContext.getApiParam();
|
||||
String nameVersion = param.fetchNameVersion();
|
||||
return zuulRouteRepository.get(nameVersion);
|
||||
ZuulTargetRoute zuulTargetRoute = zuulRouteRepository.get(nameVersion);
|
||||
if (zuulTargetRoute == null) {
|
||||
return null;
|
||||
}
|
||||
return zuulTargetRoute.getTargetRouteDefinition();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,39 +1,33 @@
|
||||
package com.gitee.sop.gatewaycommon.zuul.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteRepository;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepository;
|
||||
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
|
||||
import org.springframework.cloud.netflix.zuul.filters.Route;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 本地存放路由内容的地方
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
public class ZuulRouteRepository implements RouteRepository<ZuulServiceRouteInfo, Route> {
|
||||
public class ZuulRouteRepository implements RouteRepository<ZuulTargetRoute> {
|
||||
/**
|
||||
* key:nameVersion
|
||||
*/
|
||||
private Map<String, Route> nameVersionServiceIdMap = new ConcurrentHashMap<>(128);
|
||||
private Map<String, ZuulTargetRoute> nameVersionServiceIdMap = new ConcurrentHashMap<>(128);
|
||||
|
||||
private ServiceRouteRepository<ZuulServiceRouteInfo, Route> serviceRouteRepository = new ServiceRouteRepository<ZuulServiceRouteInfo, Route>() {
|
||||
@Override
|
||||
public String getServiceId(ZuulServiceRouteInfo serviceRouteInfo) {
|
||||
return serviceRouteInfo.getAppName();
|
||||
}
|
||||
};
|
||||
|
||||
public List<Route> listAll() {
|
||||
public List<ZuulTargetRoute> listAll() {
|
||||
return new ArrayList<>(nameVersionServiceIdMap.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Route get(String id) {
|
||||
Route route = nameVersionServiceIdMap.get(id);
|
||||
public ZuulTargetRoute get(String id) {
|
||||
ZuulTargetRoute route = nameVersionServiceIdMap.get(id);
|
||||
if (route == null) {
|
||||
throw ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getException();
|
||||
}
|
||||
@@ -41,17 +35,26 @@ public class ZuulRouteRepository implements RouteRepository<ZuulServiceRouteInfo
|
||||
}
|
||||
|
||||
@Override
|
||||
public String add(ZuulServiceRouteInfo serviceRouteInfo, Route route) {
|
||||
nameVersionServiceIdMap.put(route.getId(), route);
|
||||
serviceRouteRepository.saveRouteDefinition(serviceRouteInfo, route);
|
||||
public String add(ZuulTargetRoute targetRoute) {
|
||||
nameVersionServiceIdMap.put(targetRoute.getRouteDefinition().getId(), targetRoute);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(ZuulServiceRouteInfo serviceRouteInfo) {
|
||||
serviceRouteRepository.deleteAll(serviceRouteInfo, route -> {
|
||||
this.delete(route.getId());
|
||||
});
|
||||
public void update(ZuulTargetRoute targetRoute) {
|
||||
nameVersionServiceIdMap.put(targetRoute.getRouteDefinition().getId(), targetRoute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(String serviceId) {
|
||||
Collection<ZuulTargetRoute> values = nameVersionServiceIdMap.values();
|
||||
List<String> idList = values.stream()
|
||||
.map(zuulTargetRoute -> zuulTargetRoute.getRouteDefinition().getId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (String id : idList) {
|
||||
this.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -7,6 +7,5 @@ import lombok.Data;
|
||||
/**
|
||||
* @author thc
|
||||
*/
|
||||
@Data
|
||||
public class ZuulServiceRouteInfo extends BaseServiceRouteInfo<ZuulRouteDefinition> {
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.gitee.sop.gatewaycommon.zuul.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.AbstractTargetRoute;
|
||||
import lombok.Getter;
|
||||
import org.springframework.cloud.netflix.zuul.filters.Route;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Getter
|
||||
public class ZuulTargetRoute extends AbstractTargetRoute<ZuulServiceRouteInfo, ZuulRouteDefinition, Route> {
|
||||
|
||||
public ZuulTargetRoute(ZuulServiceRouteInfo baseServiceRouteInfo, ZuulRouteDefinition baseRouteDefinition, Route targetRoute) {
|
||||
super(baseServiceRouteInfo, baseRouteDefinition, targetRoute);
|
||||
}
|
||||
}
|
@@ -9,12 +9,13 @@ import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* 路由内容管理,新增活修改路由
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public class ZuulZookeeperRouteManager extends BaseRouteManager<ZuulServiceRouteInfo, ZuulRouteDefinition, Route> {
|
||||
public class ZuulZookeeperRouteManager extends BaseRouteManager<ZuulServiceRouteInfo, ZuulRouteDefinition, ZuulTargetRoute> {
|
||||
|
||||
public ZuulZookeeperRouteManager(Environment environment, RouteRepository<ZuulServiceRouteInfo, Route> routeRepository) {
|
||||
public ZuulZookeeperRouteManager(Environment environment, RouteRepository<ZuulTargetRoute> routeRepository) {
|
||||
super(environment, routeRepository);
|
||||
}
|
||||
|
||||
@@ -24,7 +25,13 @@ public class ZuulZookeeperRouteManager extends BaseRouteManager<ZuulServiceRoute
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Route buildRouteDefinition(ZuulServiceRouteInfo serviceRouteInfo, ZuulRouteDefinition routeDefinition) {
|
||||
return new Route(routeDefinition.getId(), RoutePathUtil.findPath(routeDefinition.getUri()), serviceRouteInfo.getAppName(), null, false, null);
|
||||
protected Class<ZuulRouteDefinition> getRouteDefinitionClass() {
|
||||
return ZuulRouteDefinition.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ZuulTargetRoute buildRouteDefinition(ZuulServiceRouteInfo serviceRouteInfo, ZuulRouteDefinition routeDefinition) {
|
||||
Route route = new Route(routeDefinition.getId(), RoutePathUtil.findPath(routeDefinition.getUri()), serviceRouteInfo.getServiceId(), null, false, null);
|
||||
return new ZuulTargetRoute(serviceRouteInfo, routeDefinition, route);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,31 @@
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.SopConstants;
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||
import org.apache.curator.retry.ExponentialBackoffRetry;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class CuratorTest extends TestCase {
|
||||
|
||||
|
||||
private String zookeeperServerAddr = "127.0.0.1:2181";
|
||||
|
||||
/**
|
||||
* 递归删除节点,只能在测试环境用。
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testDel() throws Exception {
|
||||
CuratorFramework client = CuratorFrameworkFactory.builder()
|
||||
.connectString(zookeeperServerAddr)
|
||||
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
|
||||
.build();
|
||||
|
||||
client.start();
|
||||
|
||||
client.delete().deletingChildrenIfNeeded().forPath(SopConstants.SOP_SERVICE_ROUTE_PATH);
|
||||
}
|
||||
}
|
@@ -1,127 +0,0 @@
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.MessageDigest;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class PostTest extends TestBase {
|
||||
|
||||
String url = "http://localhost:8081/zuul";
|
||||
String appKey = "test";
|
||||
String secret = "123456";
|
||||
|
||||
@Test
|
||||
public void testPost() throws Exception {
|
||||
// 业务参数
|
||||
Map<String, String> jsonMap = new HashMap<String, String>();
|
||||
jsonMap.put("id", "1");
|
||||
jsonMap.put("id", "葫芦娃");
|
||||
|
||||
String json = JSON.toJSONString(jsonMap);
|
||||
json = URLEncoder.encode(json, "utf-8");
|
||||
|
||||
// 系统参数
|
||||
Map<String, Object> param = new HashMap<String, Object>();
|
||||
param.put("name", "story.get");
|
||||
param.put("app_key", appKey);
|
||||
param.put("data", json);
|
||||
param.put("timestamp", getTime());
|
||||
param.put("version", "2.0");
|
||||
|
||||
String sign = buildSign(param, secret);
|
||||
|
||||
param.put("sign", sign);
|
||||
|
||||
System.out.println("=====请求数据=====");
|
||||
String postJson = JSON.toJSONString(param);
|
||||
System.out.println(postJson);
|
||||
|
||||
post(url, param); // 发送请求
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 构建签名
|
||||
*
|
||||
* @param paramsMap
|
||||
* 参数
|
||||
* @param secret
|
||||
* 密钥
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String buildSign(Map<String, ?> paramsMap, String secret) throws IOException {
|
||||
Set<String> keySet = paramsMap.keySet();
|
||||
List<String> paramNames = new ArrayList<String>(keySet);
|
||||
|
||||
Collections.sort(paramNames);
|
||||
|
||||
StringBuilder paramNameValue = new StringBuilder();
|
||||
|
||||
for (String paramName : paramNames) {
|
||||
paramNameValue.append(paramName).append(paramsMap.get(paramName));
|
||||
}
|
||||
|
||||
String source = secret + paramNameValue.toString() + secret;
|
||||
|
||||
return md5(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成md5,全部大写
|
||||
*
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static String md5(String message) {
|
||||
try {
|
||||
// 1 创建一个提供信息摘要算法的对象,初始化为md5算法对象
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
|
||||
// 2 将消息变成byte数组
|
||||
byte[] input = message.getBytes();
|
||||
|
||||
// 3 计算后获得字节数组,这就是那128位了
|
||||
byte[] buff = md.digest(input);
|
||||
|
||||
// 4 把数组每一字节(一个字节占八位)换成16进制连成md5字符串
|
||||
return byte2hex(buff);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 二进制转十六进制字符串
|
||||
*
|
||||
* @param bytes
|
||||
* @return
|
||||
*/
|
||||
private static String byte2hex(byte[] bytes) {
|
||||
StringBuilder sign = new StringBuilder();
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
String hex = Integer.toHexString(bytes[i] & 0xFF);
|
||||
if (hex.length() == 1) {
|
||||
sign.append("0");
|
||||
}
|
||||
sign.append(hex.toUpperCase());
|
||||
}
|
||||
return sign.toString();
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
}
|
||||
}
|
@@ -1,121 +0,0 @@
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SopPostTest extends TestBase {
|
||||
|
||||
|
||||
String url = "http://localhost:8081/zuul";
|
||||
String appKey = "test";
|
||||
String secret = "123456";
|
||||
|
||||
@Test
|
||||
public void testPost() throws Exception {
|
||||
|
||||
// 系统参数
|
||||
Map<String, Object> param = new HashMap<String, Object>();
|
||||
param.put("method", "story.get");
|
||||
param.put("app_key", appKey);
|
||||
param.put("timestamp", getTime());
|
||||
param.put("version", "2.0");
|
||||
|
||||
// 业务参数
|
||||
param.put("id", "1");
|
||||
param.put("name", "葫芦娃");
|
||||
|
||||
String sign = buildSign(param, secret);
|
||||
|
||||
param.put("sign", sign);
|
||||
|
||||
System.out.println("=====请求数据=====");
|
||||
String postJson = JSON.toJSONString(param);
|
||||
System.out.println(postJson);
|
||||
|
||||
post(url, param); // 发送请求
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建签名
|
||||
*
|
||||
* @param paramsMap 参数
|
||||
* @param secret 密钥
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String buildSign(Map<String, ?> paramsMap, String secret) throws IOException {
|
||||
Set<String> keySet = paramsMap.keySet();
|
||||
List<String> paramNames = new ArrayList<String>(keySet);
|
||||
|
||||
Collections.sort(paramNames);
|
||||
|
||||
StringBuilder paramNameValue = new StringBuilder();
|
||||
|
||||
for (String paramName : paramNames) {
|
||||
paramNameValue.append(paramName).append(paramsMap.get(paramName));
|
||||
}
|
||||
|
||||
String source = secret + paramNameValue.toString() + secret;
|
||||
|
||||
return md5(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成md5,全部大写
|
||||
*
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static String md5(String message) {
|
||||
try {
|
||||
// 1 创建一个提供信息摘要算法的对象,初始化为md5算法对象
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
|
||||
// 2 将消息变成byte数组
|
||||
byte[] input = message.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
// 3 计算后获得字节数组,这就是那128位了
|
||||
byte[] buff = md.digest(input);
|
||||
|
||||
// 4 把数组每一字节(一个字节占八位)换成16进制连成md5字符串
|
||||
return byte2hex(buff);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 二进制转十六进制字符串
|
||||
*
|
||||
* @param bytes
|
||||
* @return
|
||||
*/
|
||||
private static String byte2hex(byte[] bytes) {
|
||||
StringBuilder sign = new StringBuilder();
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
String hex = Integer.toHexString(bytes[i] & 0xFF);
|
||||
if (hex.length() == 1) {
|
||||
sign.append("0");
|
||||
}
|
||||
sign.append(hex.toUpperCase());
|
||||
}
|
||||
return sign.toString();
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
}
|
||||
|
||||
}
|
@@ -1,102 +0,0 @@
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class TestBase extends TestCase {
|
||||
public void post(String url, String postJson) throws IOException {
|
||||
HttpClient httpClient = HttpClientBuilder.create().build();
|
||||
HttpPost post = new HttpPost(url);
|
||||
// 构造消息头
|
||||
|
||||
post.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
|
||||
// 构建消息实体
|
||||
StringEntity entity = new StringEntity(postJson, Charset.forName("UTF-8"));
|
||||
entity.setContentEncoding("UTF-8");
|
||||
// 发送Json格式的数据请求
|
||||
entity.setContentType("application/json");
|
||||
post.setEntity(entity);
|
||||
|
||||
HttpResponse response = httpClient.execute(post);
|
||||
HttpEntity responseEntity = response.getEntity();
|
||||
String content = IOUtils.toString(responseEntity.getContent(), "UTF-8");
|
||||
System.out.println(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送POST请求
|
||||
* @param url
|
||||
* @return JSON或者字符串
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Object post(String url, Map<String, Object> params) throws Exception{
|
||||
CloseableHttpClient client = null;
|
||||
CloseableHttpResponse response = null;
|
||||
try{
|
||||
/**
|
||||
* 创建一个httpclient对象
|
||||
*/
|
||||
client = HttpClients.createDefault();
|
||||
/**
|
||||
* 创建一个post对象
|
||||
*/
|
||||
HttpPost post = new HttpPost(url);
|
||||
List<NameValuePair> nameValuePairs = params.entrySet().stream().map(entry -> {
|
||||
return new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
}).collect(Collectors.toList());
|
||||
/**
|
||||
* 包装成一个Entity对象
|
||||
*/
|
||||
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
|
||||
/**
|
||||
* 设置请求的内容
|
||||
*/
|
||||
post.setEntity(entity);
|
||||
/**
|
||||
* 设置请求的报文头部的编码
|
||||
*/
|
||||
post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
|
||||
/**
|
||||
* 执行post请求
|
||||
*/
|
||||
response = client.execute(post);
|
||||
/**
|
||||
* 通过EntityUitls获取返回内容
|
||||
*/
|
||||
String result = EntityUtils.toString(response.getEntity(),"UTF-8");
|
||||
System.out.println(result);
|
||||
return result;
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}finally {
|
||||
IOUtils.closeQuietly(client);
|
||||
IOUtils.closeQuietly(response);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
package com.gitee.sop.servercommon.bean;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.gitee.sop.servercommon.route.GatewayRouteDefinition;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -11,8 +10,7 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
public class ServiceApiInfo {
|
||||
private String md5;
|
||||
private String appName;
|
||||
private String serviceId;
|
||||
private List<ApiMeta> apis;
|
||||
private List<GatewayRouteDefinition> routeDefinitionList;
|
||||
|
||||
|
@@ -35,8 +35,8 @@ public class DefaultRequestMappingEvent implements RequestMappingEvent {
|
||||
|
||||
@Override
|
||||
public void onRegisterSuccess(ApiMappingHandlerMapping apiMappingHandlerMapping) {
|
||||
String appName = environment.getProperty("spring.application.name");
|
||||
if (appName == null) {
|
||||
String serviceId = environment.getProperty("spring.application.name");
|
||||
if (serviceId == null) {
|
||||
throw new RuntimeException("请在application.properties中指定spring.application.name属性");
|
||||
}
|
||||
List<ServiceApiInfo.ApiMeta> apis = this.buildApiMetaList(apiMappingHandlerMapping);
|
||||
@@ -49,9 +49,8 @@ public class DefaultRequestMappingEvent implements RequestMappingEvent {
|
||||
});
|
||||
|
||||
ServiceApiInfo serviceApiInfo = new ServiceApiInfo();
|
||||
serviceApiInfo.setAppName(appName);
|
||||
serviceApiInfo.setServiceId(serviceId);
|
||||
serviceApiInfo.setApis(apis);
|
||||
serviceApiInfo.setMd5(getMd5(apis));
|
||||
|
||||
apiMetaManager.uploadApi(serviceApiInfo);
|
||||
}
|
||||
@@ -106,11 +105,4 @@ public class DefaultRequestMappingEvent implements RequestMappingEvent {
|
||||
return path;
|
||||
}
|
||||
|
||||
protected String getMd5(List<ServiceApiInfo.ApiMeta> apis) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (ServiceApiInfo.ApiMeta api : apis) {
|
||||
sb.append(api.fetchNameVersion());
|
||||
}
|
||||
return DigestUtils.md5DigestAsHex(sb.toString().getBytes());
|
||||
}
|
||||
}
|
||||
|
@@ -20,9 +20,9 @@ public class RedisApiMetaManager implements ApiMetaManager {
|
||||
|
||||
@Override
|
||||
public void uploadApi(ServiceApiInfo serviceApiInfo) {
|
||||
log.info("上传接口信息到Redis,appName:{}, md5:{}, 接口数量:{}", serviceApiInfo.getAppName(), serviceApiInfo.getMd5(), serviceApiInfo.getApis().size());
|
||||
log.info("上传接口信息到Redis,serviceId:{}, 接口数量:{}", serviceApiInfo.getServiceId(), serviceApiInfo.getApis().size());
|
||||
String serviceApiInfoJson = JSON.toJSONString(serviceApiInfo);
|
||||
redisTemplate.opsForHash().put(API_STORE_KEY, serviceApiInfo.getAppName(), serviceApiInfoJson);
|
||||
redisTemplate.opsForHash().put(API_STORE_KEY, serviceApiInfo.getServiceId(), serviceApiInfoJson);
|
||||
// 发送订阅事件
|
||||
redisTemplate.convertAndSend(API_CHANGE_CHANNEL, serviceApiInfoJson);
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 上传路由到zookeeper
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
@@ -35,11 +36,11 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
||||
|
||||
/**
|
||||
* NameVersion=alipay.story.get1.0
|
||||
* see com.gitee.sop.gatewaycommon.route.NameVersionRoutePredicateFactory
|
||||
* see com.gitee.sop.gatewaycommon.routeDefinition.NameVersionRoutePredicateFactory
|
||||
*/
|
||||
private static String QUERY_PREDICATE_DEFINITION_TPL = "NameVersion=%s";
|
||||
|
||||
private static ServiceApiInfo.ApiMeta FIRST_API_META = new ServiceApiInfo.ApiMeta("_" + System.currentTimeMillis() + "_", "/", "0.0");
|
||||
private static ServiceApiInfo.ApiMeta FIRST_API_META = new ServiceApiInfo.ApiMeta("_first.route_", "/", "v_000");
|
||||
|
||||
private Environment environment;
|
||||
|
||||
@@ -68,27 +69,27 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
||||
routeDefinitionList.add(gatewayRouteDefinition);
|
||||
}
|
||||
ServiceRouteInfo serviceRouteInfo = new ServiceRouteInfo();
|
||||
serviceRouteInfo.setAppName(serviceApiInfo.getAppName());
|
||||
serviceRouteInfo.setServiceId(serviceApiInfo.getServiceId());
|
||||
serviceRouteInfo.setRouteDefinitionList(routeDefinitionList);
|
||||
serviceRouteInfo.setMd5(serviceApiInfo.getMd5());
|
||||
return serviceRouteInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加com.gitee.sop.gatewaycommon.route.ReadBodyRoutePredicateFactory,解决form表单获取不到问题
|
||||
* 添加com.gitee.sop.gatewaycommon.routeDefinition.ReadBodyRoutePredicateFactory,解决form表单获取不到问题
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected GatewayRouteDefinition buildReadBodyRouteDefinition(ServiceApiInfo serviceApiInfo) {
|
||||
GatewayRouteDefinition gatewayRouteDefinition = this.buildGatewayRouteDefinition(serviceApiInfo, FIRST_API_META);
|
||||
GatewayRouteDefinition readBodyRouteDefinition = this.buildGatewayRouteDefinition(serviceApiInfo, FIRST_API_META);
|
||||
readBodyRouteDefinition.setOrder(Integer.MIN_VALUE);
|
||||
|
||||
GatewayPredicateDefinition gatewayPredicateDefinition = new GatewayPredicateDefinition();
|
||||
gatewayPredicateDefinition.setName("ReadBody");
|
||||
GatewayPredicateDefinition readerBodyPredicateDefinition = this.buildNameVersionPredicateDefinition(FIRST_API_META);
|
||||
List<GatewayPredicateDefinition> predicates = Arrays.asList(gatewayPredicateDefinition, readerBodyPredicateDefinition);
|
||||
gatewayRouteDefinition.setPredicates(predicates);
|
||||
readBodyRouteDefinition.setPredicates(predicates);
|
||||
|
||||
return gatewayRouteDefinition;
|
||||
return readBodyRouteDefinition;
|
||||
}
|
||||
|
||||
protected GatewayRouteDefinition buildGatewayRouteDefinition(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) {
|
||||
@@ -114,7 +115,7 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
||||
if (!servletPath.startsWith(PATH_START_CHAR)) {
|
||||
servletPath = PATH_START_CHAR + servletPath;
|
||||
}
|
||||
return "lb://" + serviceApiInfo.getAppName() + "#" + servletPath;
|
||||
return "lb://" + serviceApiInfo.getServiceId() + "#" + servletPath;
|
||||
}
|
||||
|
||||
protected String getServletPath(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) {
|
||||
@@ -135,11 +136,10 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
||||
if (StringUtils.isEmpty(zookeeperServerAddr)) {
|
||||
throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数");
|
||||
}
|
||||
String serviceRouteInfoJson = JSON.toJSONString(serviceRouteInfo);
|
||||
CuratorFramework client = null;
|
||||
try {
|
||||
// 保存路径
|
||||
String savePath = SOP_SERVICE_ROUTE_PATH + "/" + serviceRouteInfo.getAppName();
|
||||
String savePath = SOP_SERVICE_ROUTE_PATH + "/" + serviceRouteInfo.getServiceId();
|
||||
|
||||
client = CuratorFrameworkFactory.builder()
|
||||
.connectString(zookeeperServerAddr)
|
||||
@@ -148,20 +148,15 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
||||
|
||||
client.start();
|
||||
|
||||
log.info("上传接口信息到zookeeper,path:{}, appName:{}, md5:{}, 接口数量:{}",
|
||||
log.info("上传接口信息到zookeeper,path:{}, serviceId:{}, 接口数量:{}",
|
||||
savePath,
|
||||
serviceRouteInfo.getAppName(),
|
||||
serviceRouteInfo.getMd5(),
|
||||
serviceRouteInfo.getServiceId(),
|
||||
serviceRouteInfo.getRouteDefinitionList().size());
|
||||
|
||||
client.create()
|
||||
// 如果节点存在则Curator将会使用给出的数据设置这个节点的值
|
||||
.orSetData()
|
||||
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
|
||||
.creatingParentContainersIfNeeded()
|
||||
.forPath(savePath, serviceRouteInfoJson.getBytes());
|
||||
String parentPath = this.uploadFolder(client, serviceRouteInfo);
|
||||
this.uploadRouteItems(client, serviceRouteInfo, parentPath);
|
||||
} catch (Exception e) {
|
||||
log.error("更新接口信息到zookeeper失败, appName:{}", serviceRouteInfo.getAppName(), e);
|
||||
log.error("更新接口信息到zookeeper失败, serviceId:{}", serviceRouteInfo.getServiceId(), e);
|
||||
} finally {
|
||||
if (client != null) {
|
||||
client.close();
|
||||
@@ -169,4 +164,43 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件夹内容
|
||||
* @param client
|
||||
* @param serviceRouteInfo
|
||||
* @return 返回文件夹路径
|
||||
*/
|
||||
protected String uploadFolder(CuratorFramework client, ServiceRouteInfo serviceRouteInfo) throws Exception {
|
||||
// 保存路径
|
||||
String savePath = SOP_SERVICE_ROUTE_PATH + "/" + serviceRouteInfo.getServiceId();
|
||||
String serviceRouteInfoJson = JSON.toJSONString(serviceRouteInfo);
|
||||
this.saveNode(client, savePath, serviceRouteInfoJson.getBytes());
|
||||
return savePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传路由信息
|
||||
* @param client
|
||||
* @param serviceRouteInfo
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void uploadRouteItems(CuratorFramework client, ServiceRouteInfo serviceRouteInfo, String parentPath) throws Exception {
|
||||
List<GatewayRouteDefinition> routeDefinitionList = serviceRouteInfo.getRouteDefinitionList();
|
||||
for (GatewayRouteDefinition routeDefinition : routeDefinitionList) {
|
||||
// 父目录/子目录
|
||||
String savePath = parentPath + PATH_START_CHAR + routeDefinition.getId();
|
||||
String routeDefinitionJson = JSON.toJSONString(routeDefinition);
|
||||
this.saveNode(client, savePath, routeDefinitionJson.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
protected void saveNode(CuratorFramework client, String path, byte[] data) throws Exception {
|
||||
client.create()
|
||||
// 如果节点存在则Curator将会使用给出的数据设置这个节点的值
|
||||
.orSetData()
|
||||
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
|
||||
.creatingParentContainersIfNeeded()
|
||||
.forPath(path, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -10,8 +10,8 @@ import java.util.Map;
|
||||
*/
|
||||
@Data
|
||||
public class GatewayFilterDefinition {
|
||||
//Filter Name */
|
||||
/** Filter Name */
|
||||
private String name;
|
||||
//对应的路由规则 */
|
||||
/** 对应的路由规则 */
|
||||
private Map<String, String> args = new LinkedHashMap<>();
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
package com.gitee.sop.servercommon.route;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
@@ -9,7 +10,8 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
public class ServiceRouteInfo {
|
||||
private String appName;
|
||||
private String md5;
|
||||
/** 服务名称,对应spring.application.name */
|
||||
private String serviceId;
|
||||
@JSONField(serialize = false)
|
||||
private List<GatewayRouteDefinition> routeDefinitionList;
|
||||
}
|
@@ -21,8 +21,8 @@ import java.util.Set;
|
||||
*/
|
||||
public class AlipayClientPostTest extends TestBase {
|
||||
|
||||
|
||||
String url = "http://localhost:8081/api";
|
||||
String url = "http://localhost:8081/api"; // zuul
|
||||
// String url = "http://localhost:8081"; // spring cloud gateway
|
||||
String appId = "alipay_test";
|
||||
// 支付宝私钥
|
||||
String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ=";
|
||||
|
Reference in New Issue
Block a user