From 23bbf26db7a8b507dba333a3fee9198c21e66d4e Mon Sep 17 00:00:00 2001 From: tanghc Date: Wed, 15 Jan 2020 18:08:35 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A2=84=E5=8F=91=E5=B8=83/?= =?UTF-8?q?=E7=81=B0=E5=BA=A6=E5=8F=91=E5=B8=83=E7=8E=AF=E5=A2=83=E9=80=89?= =?UTF-8?q?=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 1 + .../bridge/SopGatewayAutoConfiguration.java | 2 + .../src/main/resources/sop-bridge.properties | 4 +- .../bridge/SopGatewayAutoConfiguration.java | 3 + .../sop/gatewaycommon/bean/ApiConfig.java | 14 ++ .../sop/gatewaycommon/bean/ApiParamAware.java | 10 ++ .../sop/gatewaycommon/bean/SopConstants.java | 4 + .../BaseGatewayConfiguration.java | 30 +++++ .../gateway/filter/IndexFilter.java | 2 +- .../filter/SopLoadBalancerClientFilter.java | 32 +++++ .../GatewayLoadBalanceServerChooser.java | 29 ++++ .../loadbalancer/NacosServerIntrospector.java | 23 ++++ .../loadbalancer/SopLoadBalancerClient.java | 107 +++++++++++++++ .../gateway/route/GatewayForwardChooser.java | 2 +- .../EnvironmentServerChooser.java | 64 --------- .../EurekaEnvironmentServerChooser.java | 16 --- .../loadbalancer/LoadBalanceConfig.java | 8 ++ .../LoadBalanceServerChooser.java | 127 ++++++++++++++++++ .../loadbalancer/ServerChooserContext.java | 35 +++++ .../builder/AppIdGrayUserBuilder.java | 19 +++ .../loadbalancer/builder/GrayUserBuilder.java | 24 ++++ .../builder/IpGrayUserBuilder.java | 19 +++ .../manager/AbstractConfiguration.java | 25 +++- .../manager/EnvironmentKeys.java | 15 ++- .../sop/gatewaycommon/param/ApiParam.java | 10 ++ .../route/BaseForwardChooser.java | 25 +++- .../route/EurekaRegistryListener.java | 6 - .../zuul/loadbalancer/BaseServerChooser.java | 81 ----------- .../EnvironmentServerChooser.java | 55 ++++++++ .../ZuulLoadBalanceServerChooser.java | 24 ++++ .../zuul/route/ZuulForwardChooser.java | 2 +- .../mapping/ApiMappingHandlerMapping.java | 1 - 32 files changed, 638 insertions(+), 181 deletions(-) create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiParamAware.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/SopLoadBalancerClientFilter.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/GatewayLoadBalanceServerChooser.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/NacosServerIntrospector.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/SopLoadBalancerClient.java delete mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EnvironmentServerChooser.java delete mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EurekaEnvironmentServerChooser.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceConfig.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceServerChooser.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/ServerChooserContext.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/AppIdGrayUserBuilder.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/GrayUserBuilder.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/IpGrayUserBuilder.java delete mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/EnvironmentServerChooser.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/ZuulLoadBalanceServerChooser.java diff --git a/changelog.md b/changelog.md index 8a15f21a..828928df 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ ## 3.0.0 - 重构spring cloud gateway网关 +- 重构`预发布/灰度发布环境选择` - zuul和gateway网关二合一 - 精简配置文件 - 优化文档中心页面 diff --git a/sop-common/sop-bridge-gateway/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java b/sop-common/sop-bridge-gateway/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java index d38488fd..e454f0a1 100644 --- a/sop-common/sop-bridge-gateway/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java +++ b/sop-common/sop-bridge-gateway/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java @@ -1,12 +1,14 @@ package com.gitee.sop.bridge; import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfiguration; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * https://blog.csdn.net/seashouwang/article/details/80299571 * @author tanghc */ +@Configuration @Import(AlipayGatewayConfiguration.class) public class SopGatewayAutoConfiguration { } diff --git a/sop-common/sop-bridge-gateway/src/main/resources/sop-bridge.properties b/sop-common/sop-bridge-gateway/src/main/resources/sop-bridge.properties index f3085c07..0627a28d 100644 --- a/sop-common/sop-bridge-gateway/src/main/resources/sop-bridge.properties +++ b/sop-common/sop-bridge-gateway/src/main/resources/sop-bridge.properties @@ -4,7 +4,9 @@ spring.application.name=sop-gateway sop.secret=MZZOUSTua6LzApIWXCwEgbBmxSzpzC # 网关入口 -gateway.index-path=/ +sop.gateway-index-path=/ + +spring.main.allow-bean-definition-overriding=true # nacos cloud配置 spring.cloud.nacos.discovery.server-addr=${nacos.url} diff --git a/sop-common/sop-bridge-zuul/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java b/sop-common/sop-bridge-zuul/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java index 05762ea2..0b933ecc 100644 --- a/sop-common/sop-bridge-zuul/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java +++ b/sop-common/sop-bridge-zuul/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java @@ -2,13 +2,16 @@ package com.gitee.sop.bridge; import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * https://blog.csdn.net/seashouwang/article/details/80299571 * @author tanghc */ +@Configuration @EnableZuulProxy @Import(AlipayZuulConfiguration.class) public class SopGatewayAutoConfiguration { } + diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java index d348be42..4cdbb9c7 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java @@ -3,6 +3,9 @@ package com.gitee.sop.gatewaycommon.bean; import com.gitee.sop.gatewaycommon.gateway.result.GatewayResultExecutor; import com.gitee.sop.gatewaycommon.limit.DefaultLimitManager; import com.gitee.sop.gatewaycommon.limit.LimitManager; +import com.gitee.sop.gatewaycommon.loadbalancer.builder.AppIdGrayUserBuilder; +import com.gitee.sop.gatewaycommon.loadbalancer.builder.GrayUserBuilder; +import com.gitee.sop.gatewaycommon.loadbalancer.builder.IpGrayUserBuilder; import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager; import com.gitee.sop.gatewaycommon.manager.DefaultIPBlacklistManager; import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager; @@ -41,6 +44,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.web.server.ServerWebExchange; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -53,6 +57,9 @@ public class ApiConfig { private static ApiConfig instance = new ApiConfig(); private ApiConfig() { + grayUserBuilders = new ArrayList<>(4); + grayUserBuilders.add(new AppIdGrayUserBuilder()); + grayUserBuilders.add(new IpGrayUserBuilder()); } /** @@ -193,6 +200,13 @@ public class ApiConfig { private boolean useGateway; + private List grayUserBuilders; + + public void addGrayUserBuilder(GrayUserBuilder grayUserBuilder) { + grayUserBuilders.add(grayUserBuilder); + grayUserBuilders.sort(Comparator.comparing(GrayUserBuilder::order)); + } + public void addAppSecret(Map appSecretPair) { for (Map.Entry entry : appSecretPair.entrySet()) { this.isvManager.update(new IsvDefinition(entry.getKey(), entry.getValue())); diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiParamAware.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiParamAware.java new file mode 100644 index 00000000..51b03d06 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiParamAware.java @@ -0,0 +1,10 @@ +package com.gitee.sop.gatewaycommon.bean; + +import com.gitee.sop.gatewaycommon.param.ApiParam; + +/** + * @author tanghc + */ +public interface ApiParamAware { + ApiParam getApiParam(T t); +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java index 61fbe357..ab9cad69 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java @@ -54,4 +54,8 @@ public class SopConstants { public static final String UNKNOWN_METHOD = "_sop_unknown_method_"; public static final String UNKNOWN_VERSION = "_sop_unknown_version_"; + public static final String METADATA_ENV_KEY = "env"; + public static final String METADATA_ENV_PRE_VALUE = "pre"; + public static final String METADATA_ENV_GRAY_VALUE = "gray"; + } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java index c191985d..9c1d356f 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java @@ -8,7 +8,9 @@ import com.gitee.sop.gatewaycommon.gateway.filter.GatewayModifyResponseGatewayFi import com.gitee.sop.gatewaycommon.gateway.filter.IndexFilter; import com.gitee.sop.gatewaycommon.gateway.filter.LimitFilter; import com.gitee.sop.gatewaycommon.gateway.filter.ParameterFormatterFilter; +import com.gitee.sop.gatewaycommon.gateway.filter.SopLoadBalancerClientFilter; import com.gitee.sop.gatewaycommon.gateway.handler.GatewayExceptionHandler; +import com.gitee.sop.gatewaycommon.gateway.loadbalancer.SopLoadBalancerClient; import com.gitee.sop.gatewaycommon.gateway.route.GatewayForwardChooser; import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache; import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteRepository; @@ -17,6 +19,10 @@ import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.gateway.config.LoadBalancerProperties; +import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.core.Ordered; @@ -111,4 +117,28 @@ public class BaseGatewayConfiguration extends AbstractConfiguration { GatewayForwardChooser gatewayForwardChooser() { return new GatewayForwardChooser(); } + + /** + * 扩展默认的负载均衡选择,默认使用的是RibbonLoadBalancerClient。当配置了pre.domain时才生效 + * @param clientFactory + * @return + */ + @Primary + @Bean + LoadBalancerClient sopLoadBalancerClient(SpringClientFactory clientFactory) { + return new SopLoadBalancerClient(clientFactory); + } + + /** + * 扩展默认的负载均衡过滤器,默认是LoadBalancerClientFilter。当配置了pre.domain时才生效 + * @param sopLoadBalancerClient SopLoadBalancerClient + * @param loadBalancerProperties loadBalancerProperties + * @return + */ + @Primary + @Bean + LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient sopLoadBalancerClient, LoadBalancerProperties loadBalancerProperties) { + return new SopLoadBalancerClientFilter(sopLoadBalancerClient, loadBalancerProperties); + } + } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java index 5441eb1d..9af4a5e3 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java @@ -43,7 +43,7 @@ public class IndexFilter implements WebFilter { private static final String REST_PATH_PREFIX = "/rest"; private static final String SOP_PATH_PREFIX = "/sop"; - @Value("${gateway.index-path:/}") + @Value("${sop.gateway-index-path:/}") private String indexPath; @Autowired diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/SopLoadBalancerClientFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/SopLoadBalancerClientFilter.java new file mode 100644 index 00000000..b8e74c55 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/SopLoadBalancerClientFilter.java @@ -0,0 +1,32 @@ +package com.gitee.sop.gatewaycommon.gateway.filter; + +import com.gitee.sop.gatewaycommon.gateway.loadbalancer.SopLoadBalancerClient; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.gateway.config.LoadBalancerProperties; +import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter; +import org.springframework.web.server.ServerWebExchange; + +import java.net.URI; + +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; + +/** + * 扩展负载均衡过滤器 + * @author tanghc + */ +public class SopLoadBalancerClientFilter extends LoadBalancerClientFilter { + public SopLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) { + super(loadBalancer, properties); + } + + @Override + protected ServiceInstance choose(ServerWebExchange exchange) { + if (loadBalancer instanceof SopLoadBalancerClient) { + SopLoadBalancerClient sopLoadBalancerClient = (SopLoadBalancerClient)loadBalancer; + return sopLoadBalancerClient.choose(((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost(), exchange); + } else { + return super.choose(exchange); + } + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/GatewayLoadBalanceServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/GatewayLoadBalanceServerChooser.java new file mode 100644 index 00000000..8a6f8886 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/GatewayLoadBalanceServerChooser.java @@ -0,0 +1,29 @@ +package com.gitee.sop.gatewaycommon.gateway.loadbalancer; + +import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; +import com.gitee.sop.gatewaycommon.loadbalancer.LoadBalanceServerChooser; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.web.server.ServerWebExchange; + +/** + * @author tanghc + */ +public class GatewayLoadBalanceServerChooser extends LoadBalanceServerChooser { + + public GatewayLoadBalanceServerChooser(SpringClientFactory clientFactory) { + this.setClientFactory(clientFactory); + } + + @Override + public String getHost(ServerWebExchange exchange) { + return exchange.getRequest().getURI().getHost(); + } + + @Override + public ApiParam getApiParam(ServerWebExchange exchange) { + return ServerWebExchangeUtil.getApiParam(exchange); + } + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/NacosServerIntrospector.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/NacosServerIntrospector.java new file mode 100644 index 00000000..565fa79a --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/NacosServerIntrospector.java @@ -0,0 +1,23 @@ +package com.gitee.sop.gatewaycommon.gateway.loadbalancer; + +import com.netflix.loadbalancer.Server; +import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer; +import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector; + +import java.util.Map; + +/** + * @author tanghc + */ +public class NacosServerIntrospector extends DefaultServerIntrospector { + + @Override + public Map getMetadata(Server server) { + if (server instanceof NacosServer) { + NacosServer discoveryServer = (NacosServer)server; + return discoveryServer.getInstance().getMetadata(); + } else { + return super.getMetadata(server); + } + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/SopLoadBalancerClient.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/SopLoadBalancerClient.java new file mode 100644 index 00000000..9f38866b --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/SopLoadBalancerClient.java @@ -0,0 +1,107 @@ +package com.gitee.sop.gatewaycommon.gateway.loadbalancer; + +import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; +import com.gitee.sop.gatewaycommon.loadbalancer.ServerChooserContext; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.Server; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; +import org.springframework.cloud.netflix.ribbon.RibbonUtils; +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.web.server.ServerWebExchange; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +/** + * 重写负载均衡处理。 + * 默认使用的是RibbonLoadBalancerClient类,详见org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration#loadBalancerClient() + * + * @author tanghc + */ +public class SopLoadBalancerClient extends RibbonLoadBalancerClient implements ServerChooserContext { + + private final SpringClientFactory clientFactory; + private GatewayLoadBalanceServerChooser loadBalanceServerChooser; + + public SopLoadBalancerClient(SpringClientFactory clientFactory) { + super(clientFactory); + this.clientFactory = clientFactory; + this.loadBalanceServerChooser = new GatewayLoadBalanceServerChooser(clientFactory); + } + + /** + * New: Select a server using a 'key'. + */ + @Override + public ServiceInstance choose(String serviceId, Object hint) { + return loadBalanceServerChooser.choose( + serviceId + , (ServerWebExchange) hint + , this.getLoadBalancer(serviceId) + , () -> super.choose(serviceId, hint) + , (servers) -> getRibbonServer(serviceId, servers) + ); + } + + @Override + public ApiParam getApiParam(ServerWebExchange exchange) { + return ServerWebExchangeUtil.getApiParam(exchange); + } + + @Override + public String getHost(ServerWebExchange exchange) { + return exchange.getRequest().getURI().getHost(); + } + + private RibbonServer getRibbonServer(String serviceId, List servers) { + Server server = this.chooseRandomServer(servers); + if (server == null) { + return null; + } + return new RibbonServer( + serviceId + , server + , isSecure(server, serviceId) + , serverIntrospector(serviceId).getMetadata(server) + ); + } + + /** + * 随机选取一台实例 + * + * @param servers 服务列表 + * @return 返回实例,没有返回null + */ + private Server chooseRandomServer(List servers) { + if (servers.isEmpty()) { + return null; + } + int serverCount = servers.size(); + // 随机选取一台实例 + int index = chooseRandomInt(serverCount); + return servers.get(index); + } + + private int chooseRandomInt(int serverCount) { + return ThreadLocalRandom.current().nextInt(serverCount); + } + + private ServerIntrospector serverIntrospector(String serviceId) { + ServerIntrospector serverIntrospector = this.clientFactory.getInstance(serviceId, + ServerIntrospector.class); + if (serverIntrospector == null) { + serverIntrospector = new DefaultServerIntrospector(); + } + return serverIntrospector; + } + + private boolean isSecure(Server server, String serviceId) { + IClientConfig config = this.clientFactory.getClientConfig(serviceId); + ServerIntrospector serverIntrospector = serverIntrospector(serviceId); + return RibbonUtils.isSecure(config, serverIntrospector, server); + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayForwardChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayForwardChooser.java index 219b1ec4..93feae5c 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayForwardChooser.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayForwardChooser.java @@ -14,7 +14,7 @@ public class GatewayForwardChooser extends BaseForwardChooser private static final String VALIDATE_ERROR_PATH = "/sop/validateError"; @Override - protected ApiParam getApiParam(ServerWebExchange exchange) { + public ApiParam getApiParam(ServerWebExchange exchange) { return ServerWebExchangeUtil.getApiParam(exchange); } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EnvironmentServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EnvironmentServerChooser.java deleted file mode 100644 index a3e7ddea..00000000 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EnvironmentServerChooser.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.gitee.sop.gatewaycommon.loadbalancer; - -import com.gitee.sop.gatewaycommon.bean.SpringContext; -import com.gitee.sop.gatewaycommon.zuul.loadbalancer.BaseServerChooser; -import com.netflix.loadbalancer.Server; -import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer; -import org.springframework.core.env.Environment; - -import javax.servlet.http.HttpServletRequest; -import java.util.Map; - -/** - * 预发布、灰度环境选择,参考自:https://segmentfault.com/a/1190000017412946 - * - * @author tanghc - */ -public class EnvironmentServerChooser extends BaseServerChooser { - - private static final String MEDATA_KEY_ENV = "env"; - private static final String ENV_PRE_VALUE = "pre"; - private static final String ENV_GRAY_VALUE = "gray"; - - /** - * 预发布机器域名 - */ - private static final String PRE_DOMAIN = "localhost"; - - @Override - protected boolean isPreServer(Server server) { - String env = getEnvValue(server); - return ENV_PRE_VALUE.equals(env); - } - - @Override - protected boolean isGrayServer(Server server) { - String env = getEnvValue(server); - return ENV_GRAY_VALUE.equals(env); - } - - private String getEnvValue(Server server) { - // eureka存储的metadata - Map metadata = getMetada(server); - return metadata.get(MEDATA_KEY_ENV); - } - - protected Map getMetada(Server server) { - return ((NacosServer) server).getMetadata(); - } - - - /** - * 通过判断hostname来确定是否是预发布请求,可修改此方法实现自己想要的 - * - * @param request request - * @return 返回true:可以进入到预发环境 - */ - @Override - protected boolean canVisitPre(Server server, HttpServletRequest request) { - String serverName = request.getServerName(); - String domain = SpringContext.getBean(Environment.class).getProperty("pre.domain", PRE_DOMAIN); - return domain.equals(serverName); - } - -} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EurekaEnvironmentServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EurekaEnvironmentServerChooser.java deleted file mode 100644 index f67ba85b..00000000 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EurekaEnvironmentServerChooser.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gitee.sop.gatewaycommon.loadbalancer; - -import com.netflix.loadbalancer.Server; -import com.netflix.niws.loadbalancer.DiscoveryEnabledServer; - -import java.util.Map; - -/** - * @author tanghc - */ -public class EurekaEnvironmentServerChooser extends EnvironmentServerChooser { - @Override - protected Map getMetada(Server server) { - return ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata(); - } -} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceConfig.java new file mode 100644 index 00000000..77f6c009 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceConfig.java @@ -0,0 +1,8 @@ +package com.gitee.sop.gatewaycommon.loadbalancer; + +/** + * @author tanghc + */ +public class LoadBalanceConfig { + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceServerChooser.java new file mode 100644 index 00000000..0cea6478 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceServerChooser.java @@ -0,0 +1,127 @@ +package com.gitee.sop.gatewaycommon.loadbalancer; + +import com.gitee.sop.gatewaycommon.bean.SopConstants; +import com.gitee.sop.gatewaycommon.bean.SpringContext; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.Server; +import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector; +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * 预发布、灰度发布服务器选择 + * + * @author tanghc + */ +public abstract class LoadBalanceServerChooser implements ServerChooserContext { + + private SpringClientFactory clientFactory; + + /** + * 选择服务器 + * + * @param serviceId serviceId,仅gateway网关有作用 + * @param exchange 请求上下文 + * @param loadBalancer loadBalancer + * @param superChooser 父类默认的选择 + * @param serverChooserFunction 执行选择操作 + * @return 返回服务器实例 + */ + public R choose( + String serviceId + , T exchange + , ILoadBalancer loadBalancer + , Supplier superChooser + , Function, R> serverChooserFunction) { + // 获取所有服务实例 + List servers = loadBalancer.getReachableServers(); + + // 存放预发服务器 + List preServers = new ArrayList<>(4); + // 存放灰度发布服务器 + List grayServers = new ArrayList<>(4); + // 存放非预发服务器 + List notPreServers = new ArrayList<>(4); + + for (Server server : servers) { + // 获取实例metadata + Map metadata = getMetadata(serviceId, server); + // 是否开启了预发模式 + if (this.isPreServer(metadata)) { + preServers.add(server); + } else if (this.isGrayServer(metadata)) { + grayServers.add(server); + } else { + notPreServers.add(server); + } + } + notPreServers.addAll(grayServers); + // 如果没有开启预发布服务和灰度发布,直接用默认的方式 + if (preServers.isEmpty() && grayServers.isEmpty()) { + return superChooser.get(); + } + // 如果是从预发布域名访问过来,则认为是预发布请求 + if (this.isRequestFromPreDomain(exchange)) { + return serverChooserFunction.apply(preServers); + } + // 如果是灰度请求 + if (this.isRequestGrayServer(exchange)) { + return serverChooserFunction.apply(grayServers); + } + + // 到这里说明不能访问预发/灰度服务器,则需要路由到非预发服务器 + return serverChooserFunction.apply(notPreServers); + } + + protected Map getMetadata(String serviceId, Server server) { + return serverIntrospector(serviceId).getMetadata(server); + } + + protected SpringClientFactory getSpringClientFactory() { + if (clientFactory == null) { + clientFactory = SpringContext.getBean(SpringClientFactory.class); + } + return clientFactory; + } + + public void setClientFactory(SpringClientFactory clientFactory) { + this.clientFactory = clientFactory; + } + + private ServerIntrospector serverIntrospector(String serviceId) { + ServerIntrospector serverIntrospector = getSpringClientFactory().getInstance(serviceId, + ServerIntrospector.class); + if (serverIntrospector == null) { + serverIntrospector = new DefaultServerIntrospector(); + } + return serverIntrospector; + } + + /** + * 是否是预发布服务器 + * + * @param metadata metadata + * @return true:是 + */ + private boolean isPreServer(Map metadata) { + return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_PRE_VALUE); + } + + /** + * 是否是灰度发布服务器 + * + * @param metadata metadata + * @return true:是 + */ + private boolean isGrayServer(Map metadata) { + return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_GRAY_VALUE); + } + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/ServerChooserContext.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/ServerChooserContext.java new file mode 100644 index 00000000..8b38406b --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/ServerChooserContext.java @@ -0,0 +1,35 @@ +package com.gitee.sop.gatewaycommon.loadbalancer; + +import com.gitee.sop.gatewaycommon.bean.ApiParamAware; +import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import org.apache.commons.lang.ArrayUtils; +import org.springframework.util.StringUtils; + +/** + * @author tanghc + */ +public interface ServerChooserContext extends ApiParamAware { + + /** + * 通过判断hostname来确定是否是预发布请求 + * + * @param t t + * @return 返回true:可以进入到预发环境 + */ + default boolean isRequestFromPreDomain(T t) { + String domain = EnvironmentKeys.PRE_DOMAIN.getValue(); + if (StringUtils.isEmpty(domain)) { + return false; + } + String[] domains = domain.split("\\,"); + return ArrayUtils.contains(domains, getHost(t)); + } + + default boolean isRequestGrayServer(T t) { + ApiParam apiParam = getApiParam(t); + return apiParam.isGrayRequest(); + } + + String getHost(T t); +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/AppIdGrayUserBuilder.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/AppIdGrayUserBuilder.java new file mode 100644 index 00000000..1d4a6027 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/AppIdGrayUserBuilder.java @@ -0,0 +1,19 @@ +package com.gitee.sop.gatewaycommon.loadbalancer.builder; + +import com.gitee.sop.gatewaycommon.param.ApiParam; + +/** + * @author tanghc + */ +public class AppIdGrayUserBuilder implements GrayUserBuilder { + + @Override + public String buildGrayUserKey(ApiParam apiParam) { + return apiParam.fetchAppKey(); + } + + @Override + public int order() { + return 0; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/GrayUserBuilder.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/GrayUserBuilder.java new file mode 100644 index 00000000..7e23eecb --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/GrayUserBuilder.java @@ -0,0 +1,24 @@ +package com.gitee.sop.gatewaycommon.loadbalancer.builder; + +import com.gitee.sop.gatewaycommon.param.ApiParam; + +/** + * @author tanghc + */ +public interface GrayUserBuilder { + + /** + * 获取灰度用户key + * + * @param apiParam apiParam + * @return 返回用户key + */ + String buildGrayUserKey(ApiParam apiParam); + + /** + * 优先级,数字小优先 + * + * @return 返回数字 + */ + int order(); +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/IpGrayUserBuilder.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/IpGrayUserBuilder.java new file mode 100644 index 00000000..c629b183 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/IpGrayUserBuilder.java @@ -0,0 +1,19 @@ +package com.gitee.sop.gatewaycommon.loadbalancer.builder; + +import com.gitee.sop.gatewaycommon.param.ApiParam; + +/** + * @author tanghc + */ +public class IpGrayUserBuilder implements GrayUserBuilder { + + @Override + public String buildGrayUserKey(ApiParam apiParam) { + return apiParam.fetchIp(); + } + + @Override + public int order() { + return 1; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java index c8b8845a..d2a7c7ac 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java @@ -4,15 +4,16 @@ import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.bean.BeanInitializer; import com.gitee.sop.gatewaycommon.bean.SpringContext; +import com.gitee.sop.gatewaycommon.gateway.loadbalancer.NacosServerIntrospector; import com.gitee.sop.gatewaycommon.limit.LimitManager; import com.gitee.sop.gatewaycommon.loadbalancer.SopPropertiesFactory; import com.gitee.sop.gatewaycommon.message.ErrorFactory; import com.gitee.sop.gatewaycommon.param.ParameterFormatter; -import com.gitee.sop.gatewaycommon.route.ServiceRouteListener; import com.gitee.sop.gatewaycommon.route.EurekaRegistryListener; import com.gitee.sop.gatewaycommon.route.NacosRegistryListener; import com.gitee.sop.gatewaycommon.route.RegistryListener; import com.gitee.sop.gatewaycommon.route.ServiceListener; +import com.gitee.sop.gatewaycommon.route.ServiceRouteListener; import com.gitee.sop.gatewaycommon.secret.IsvManager; import com.gitee.sop.gatewaycommon.session.SessionManager; import com.gitee.sop.gatewaycommon.validate.SignConfig; @@ -23,6 +24,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.client.discovery.event.HeartbeatEvent; import org.springframework.cloud.netflix.ribbon.PropertiesFactory; +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.cloud.netflix.ribbon.eureka.EurekaServerIntrospector; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEvent; @@ -159,6 +162,26 @@ public class AbstractConfiguration implements ApplicationContextAware { return createCorsFilter(); } + /** + * 负责获取nacos实例的metadata + * @return + */ + @Bean + @ConditionalOnProperty("spring.cloud.nacos.discovery.server-addr") + ServerIntrospector nacosServerIntrospector() { + return new NacosServerIntrospector(); + } + + /** + * 负责获取eureka实例的metadata + * @return + */ + @Bean + @ConditionalOnProperty("eureka.client.serviceUrl.defaultZone") + ServerIntrospector eurekaServerIntrospector() { + return new EurekaServerIntrospector(); + } + protected CorsFilter createCorsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); this.registerCorsConfiguration(source); diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvironmentKeys.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvironmentKeys.java index f05fa2eb..3fa1b20f 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvironmentKeys.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvironmentKeys.java @@ -1,6 +1,6 @@ package com.gitee.sop.gatewaycommon.manager; -import com.gitee.sop.gatewaycommon.loadbalancer.EnvironmentServerChooser; +import com.gitee.sop.gatewaycommon.zuul.loadbalancer.EnvironmentServerChooser; public enum EnvironmentKeys { SPRING_PROFILES_ACTIVE("spring.profiles.active", "default"), @@ -9,7 +9,7 @@ public enum EnvironmentKeys { */ SPRING_APPLICATION_NAME("spring.application.name"), /** - * 指定负载均衡规则类,默认使用com.gitee.sop.gateway.loadbalancer.PreEnvironmentServerChooser + * 指定负载均衡规则类 */ ZUUL_CUSTOM_RULE_CLASSNAME("zuul.custom-rule-classname", EnvironmentServerChooser.class.getName()), @@ -35,8 +35,11 @@ public enum EnvironmentKeys { /** * 排除其它微服务,正则形式,多个用英文逗号隔开 */ - SOP_SERVICE_EXCLUDE_REGEX("sop.service.exclude-regex") - ; + SOP_SERVICE_EXCLUDE_REGEX("sop.service.exclude-regex"), + /** + * 预发布域名 + */ + PRE_DOMAIN("pre.domain"); private String key; private String defaultValue; @@ -57,4 +60,8 @@ public enum EnvironmentKeys { public String getValue() { return EnvironmentContext.getValue(key, defaultValue); } + + public String getValue(String defaultValue) { + return EnvironmentContext.getValue(key, defaultValue); + } } \ No newline at end of file diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java index 4d48d78f..1e3559b1 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java @@ -31,6 +31,8 @@ public class ApiParam extends JSONObject implements Param { private String ip; + private boolean isGrayRequest; + private transient UploadContext uploadContext; public void fitNameVersion() { @@ -248,4 +250,12 @@ public class ApiParam extends JSONObject implements Param { public String fetchIp() { return ip; } + + public boolean isGrayRequest() { + return isGrayRequest; + } + + public void setGrayRequest(boolean grayRequest) { + isGrayRequest = grayRequest; + } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java index 254560c9..0b7715d5 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java @@ -1,23 +1,28 @@ package com.gitee.sop.gatewaycommon.route; +import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.bean.RouteDefinition; +import com.gitee.sop.gatewaycommon.bean.ApiParamAware; import com.gitee.sop.gatewaycommon.bean.TargetRoute; +import com.gitee.sop.gatewaycommon.loadbalancer.builder.GrayUserBuilder; import com.gitee.sop.gatewaycommon.manager.EnvGrayManager; import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext; import com.gitee.sop.gatewaycommon.param.ApiParam; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; +import javax.annotation.PostConstruct; +import java.util.Comparator; +import java.util.List; + /** * @author tanghc */ -public abstract class BaseForwardChooser implements ForwardChooser { +public abstract class BaseForwardChooser implements ForwardChooser, ApiParamAware { @Autowired private EnvGrayManager envGrayManager; - protected abstract ApiParam getApiParam(T t); - @Override public ForwardInfo getForwardInfo(T t) { ApiParam apiParam = getApiParam(t); @@ -30,10 +35,11 @@ public abstract class BaseForwardChooser implements ForwardChooser { // 如果服务在灰度阶段,返回一个灰度版本号 String grayVersion = envGrayManager.getVersion(serviceId, nameVersion); // 如果是灰度环境 - if (grayVersion != null && envGrayManager.containsKey(serviceId, apiParam.fetchAppKey())) { + if (grayVersion != null && isGrayUser(serviceId, apiParam)) { String newNameVersion = apiParam.fetchName() + grayVersion; TargetRoute targetRouteDest = RouteRepositoryContext.getRouteRepository().get(newNameVersion); if (targetRouteDest != null) { + apiParam.setGrayRequest(true); if (BooleanUtils.toBoolean(routeDefinitionOrig.getCompatibleMode())) { version = grayVersion; } else { @@ -46,4 +52,15 @@ public abstract class BaseForwardChooser implements ForwardChooser { return new ForwardInfo(path, version); } + protected boolean isGrayUser(String serviceId, ApiParam apiParam) { + List grayUserBuilders = ApiConfig.getInstance().getGrayUserBuilders(); + for (GrayUserBuilder grayUserBuilder : grayUserBuilders) { + String userKey = grayUserBuilder.buildGrayUserKey(apiParam); + if (envGrayManager.containsKey(serviceId, userKey)) { + return true; + } + } + return false; + } + } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java index 6eb37113..55f71a3a 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java @@ -1,8 +1,6 @@ package com.gitee.sop.gatewaycommon.route; import com.gitee.sop.gatewaycommon.bean.InstanceDefinition; -import com.gitee.sop.gatewaycommon.loadbalancer.EurekaEnvironmentServerChooser; -import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys; import com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.shared.Application; import com.netflix.discovery.shared.Applications; @@ -25,10 +23,6 @@ import java.util.stream.Collectors; */ public class EurekaRegistryListener extends BaseRegistryListener { - static { - System.setProperty(EnvironmentKeys.ZUUL_CUSTOM_RULE_CLASSNAME.getKey(), EurekaEnvironmentServerChooser.class.getName()); - } - private Set cacheServices = new HashSet<>(); @Override diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java deleted file mode 100644 index d08db36b..00000000 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.gitee.sop.gatewaycommon.zuul.loadbalancer; - -import com.google.common.base.Optional; -import com.netflix.loadbalancer.ILoadBalancer; -import com.netflix.loadbalancer.Server; -import com.netflix.loadbalancer.ZoneAvoidanceRule; -import com.netflix.zuul.context.RequestContext; -import lombok.extern.slf4j.Slf4j; - -import javax.servlet.http.HttpServletRequest; -import java.util.List; -import java.util.stream.Collectors; - -/** - * 服务实例选择器 - * - * @author tanghc - */ -@Slf4j -public abstract class BaseServerChooser extends ZoneAvoidanceRule { - - - /** - * 是否是预发布服务器 - * @param server 服务器 - * @return true:是 - */ - protected abstract boolean isPreServer(Server server); - - /** - * 是否是灰度发布服务器 - * @param server 服务器 - * @return true:是 - */ - protected abstract boolean isGrayServer(Server server); - - /** - * 能否访问预发布 - * @param server 预发布服务器 - * @param request request - * @return true:能 - */ - protected abstract boolean canVisitPre(Server server, HttpServletRequest request); - - - @Override - public Server choose(Object key) { - ILoadBalancer lb = getLoadBalancer(); - // 获取服务实例列表 - List allServers = lb.getAllServers(); - HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); - - List preServers = allServers.stream() - .filter(this::isPreServer) - .filter(server -> canVisitPre(server, request)) - .collect(Collectors.toList()); - - if (!preServers.isEmpty()) { - return this.doChoose(preServers, key); - } - - List grayServers = allServers.stream() - .filter(this::isGrayServer) - .collect(Collectors.toList()); - if (!grayServers.isEmpty()) { - return doChoose(grayServers, key); - } - - return super.choose(key); - } - - protected Server doChoose(List servers, Object key) { - Optional server = getPredicate().chooseRoundRobinAfterFiltering(servers, key); - if (server.isPresent()) { - return server.get(); - } else { - return null; - } - } - -} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/EnvironmentServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/EnvironmentServerChooser.java new file mode 100644 index 00000000..a9a6c477 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/EnvironmentServerChooser.java @@ -0,0 +1,55 @@ +package com.gitee.sop.gatewaycommon.zuul.loadbalancer; + +import com.gitee.sop.gatewaycommon.loadbalancer.ServerChooserContext; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.zuul.ZuulContext; +import com.google.common.base.Optional; +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.ZoneAvoidanceRule; +import com.netflix.zuul.context.RequestContext; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 预发布、灰度环境选择,参考自:https://segmentfault.com/a/1190000017412946 + * + * @author tanghc + */ +@Slf4j +public class EnvironmentServerChooser extends ZoneAvoidanceRule implements ServerChooserContext { + + private ZuulLoadBalanceServerChooser loadBalanceServerChooser = new ZuulLoadBalanceServerChooser(); + + @Override + public String getHost(HttpServletRequest request) { + return request.getServerName(); + } + + @Override + public ApiParam getApiParam(HttpServletRequest request) { + return ZuulContext.getApiParam(); + } + + @Override + public Server choose(Object key) { + return loadBalanceServerChooser.choose( + String.valueOf(key) + , RequestContext.getCurrentContext().getRequest() + , getLoadBalancer() + , () -> super.choose(key) + , (servers) -> this.doChoose(servers, key) + ); + } + + protected Server doChoose(List servers, Object key) { + Optional server = getPredicate().chooseRoundRobinAfterFiltering(servers, key); + if (server.isPresent()) { + return server.get(); + } else { + return null; + } + } + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/ZuulLoadBalanceServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/ZuulLoadBalanceServerChooser.java new file mode 100644 index 00000000..b1046ee9 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/ZuulLoadBalanceServerChooser.java @@ -0,0 +1,24 @@ +package com.gitee.sop.gatewaycommon.zuul.loadbalancer; + +import com.gitee.sop.gatewaycommon.loadbalancer.LoadBalanceServerChooser; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.zuul.ZuulContext; +import com.netflix.loadbalancer.Server; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author tanghc + */ +public class ZuulLoadBalanceServerChooser extends LoadBalanceServerChooser { + + @Override + public String getHost(HttpServletRequest request) { + return request.getServerName(); + } + + @Override + public ApiParam getApiParam(HttpServletRequest request) { + return ZuulContext.getApiParam(); + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulForwardChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulForwardChooser.java index cea835d5..625d129f 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulForwardChooser.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulForwardChooser.java @@ -11,7 +11,7 @@ import com.netflix.zuul.context.RequestContext; public class ZuulForwardChooser extends BaseForwardChooser { @Override - protected ApiParam getApiParam(RequestContext requestContext) { + public ApiParam getApiParam(RequestContext requestContext) { return ZuulContext.getApiParam(); } diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java index 8185d7f7..1d706005 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java @@ -19,7 +19,6 @@ import java.lang.reflect.Method; */ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping implements PriorityOrdered { - private static StringValueResolver stringValueResolver = new ApiMappingStringValueResolver(); private static StringValueResolver stringValueResolverMVC = new ApiMappingStringValueResolverMVC(); @Override