升级springboot版本至2.6.16

升级springcloud alibaba版本至2021.0.5.0
升级springcloud版本至2021.0.5
移除ribbon,使用spring cloud loadbalancer
This commit is contained in:
整洁架构
2024-06-12 23:17:25 +08:00
parent 19022bdbe1
commit 6053a3f0ec
80 changed files with 445 additions and 822 deletions

View File

@@ -43,11 +43,6 @@
<artifactId>commons-collections</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
@@ -104,7 +99,23 @@
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
</dependencies>

View File

@@ -2,9 +2,6 @@ package com.gitee.sop.gatewaycommon.bean;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* @author tanghc
*/

View File

@@ -4,17 +4,9 @@ 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.interceptor.RouteInterceptor;
import com.gitee.sop.gatewaycommon.limit.LimitManager;
import com.gitee.sop.gatewaycommon.manager.EnvGrayManager;
import com.gitee.sop.gatewaycommon.manager.EnvironmentContext;
import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys;
import com.gitee.sop.gatewaycommon.manager.IPBlacklistManager;
import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager;
import com.gitee.sop.gatewaycommon.manager.LimitConfigManager;
import com.gitee.sop.gatewaycommon.manager.RouteConfigManager;
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
import com.gitee.sop.gatewaycommon.manager.*;
import com.gitee.sop.gatewaycommon.message.ErrorFactory;
import com.gitee.sop.gatewaycommon.monitor.MonitorManager;
import com.gitee.sop.gatewaycommon.param.ParameterFormatter;
@@ -35,7 +27,6 @@ import org.springframework.boot.ApplicationRunner;
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.ServerIntrospector;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
@@ -67,9 +58,6 @@ public class AbstractConfiguration implements ApplicationContextAware, Applicati
@Autowired
protected Environment environment;
@Autowired
private RegistryListener registryListener;
protected ApplicationContext applicationContext;
@Override
@@ -95,7 +83,7 @@ public class AbstractConfiguration implements ApplicationContextAware, Applicati
lock.unlock();
}
}
registryListener.onEvent(heartbeatEvent);
applicationContext.getBean(RegistryListener.class).onEvent(heartbeatEvent);
}
@Bean
@@ -190,18 +178,6 @@ public class AbstractConfiguration implements ApplicationContextAware, Applicati
return corsConfiguration;
}
/**
* 负责获取nacos实例的metadata
* @return
*/
@Bean
@ConditionalOnProperty("spring.cloud.nacos.discovery.server-addr")
ServerIntrospector nacosServerIntrospector() {
return new NacosServerIntrospector();
}
@Override
public void run(ApplicationArguments args) throws Exception {
this.isStartupCompleted = true;

View File

@@ -1,8 +1,6 @@
package com.gitee.sop.gatewaycommon.config;
import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -12,6 +10,5 @@ import org.springframework.context.annotation.Import;
*/
@Configuration
@Import(AlipayGatewayConfiguration.class)
@AutoConfigureBefore(RibbonAutoConfiguration.class)
public class SopGatewayAutoConfiguration extends BaseGatewayAutoConfiguration {
}

View File

@@ -1,25 +1,19 @@
package com.gitee.sop.gatewaycommon.gateway.configuration;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.config.AbstractConfiguration;
import com.gitee.sop.gatewaycommon.gateway.filter.GatewayModifyResponseGatewayFilter;
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;
import com.gitee.sop.gatewaycommon.config.AbstractConfiguration;
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;
@@ -100,25 +94,4 @@ public class BaseGatewayConfiguration extends AbstractConfiguration {
return new GatewayForwardChooser();
}
/**
* 扩展默认的负载均衡选择默认使用的是RibbonLoadBalancerClient
* @param clientFactory
* @return
*/
@Bean
LoadBalancerClient loadBalancerClient(SpringClientFactory clientFactory) {
return new SopLoadBalancerClient(clientFactory);
}
/**
* 扩展默认的负载均衡过滤器默认是LoadBalancerClientFilter
* @param sopLoadBalancerClient SopLoadBalancerClient
* @param loadBalancerProperties loadBalancerProperties
* @return
*/
@Bean
LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient sopLoadBalancerClient, LoadBalancerProperties loadBalancerProperties) {
return new SopLoadBalancerClientFilter(sopLoadBalancerClient, loadBalancerProperties);
}
}

View File

@@ -1,9 +1,10 @@
package com.gitee.sop.gatewaycommon.gateway.controller;
import com.gitee.sop.gatewaycommon.bean.SpringContext;
import com.gitee.sop.gatewaycommon.gateway.loadbalancer.SopLoadBalancerClient;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.webflux.ProxyExchange;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
@@ -12,6 +13,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Random;
/**
* 处理restful请求
* @author tanghc
@@ -21,6 +25,8 @@ public class RestfulController {
@Value("${sop.restful.path:/rest}")
private String prefix;
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("${sop.restful.path:/rest}/**")
public Mono<ResponseEntity<byte[]>> proxy(ProxyExchange<byte[]> proxy, ServerWebExchange exchange) {
@@ -32,7 +38,14 @@ public class RestfulController {
targetPath = targetPath + "?" + rawQuery;
}
// 负载均衡
ServiceInstance serviceInstance = SpringContext.getBean(SopLoadBalancerClient.class).choose(serviceId, exchange);
List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
if (CollectionUtils.isEmpty(instances)) {
return Mono.error(new RuntimeException("serviceId: " + serviceId + " not found"));
}
ServiceInstance serviceInstance = instances.stream()
.skip(new Random().nextInt(instances.size()))
.findFirst()
.orElse(null);
String uri = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + targetPath;
return proxy.uri(uri).forward();
}

View File

@@ -1,36 +0,0 @@
package com.gitee.sop.gatewaycommon.gateway.filter;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
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) {
ServiceInstance serviceInstance;
if (loadBalancer instanceof SopLoadBalancerClient) {
SopLoadBalancerClient sopLoadBalancerClient = (SopLoadBalancerClient)loadBalancer;
serviceInstance = sopLoadBalancerClient.choose(((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost(), exchange);
} else {
serviceInstance = super.choose(exchange);
}
exchange.getAttributes().put(SopConstants.TARGET_SERVICE, serviceInstance);
return serviceInstance;
}
}

View File

@@ -1,29 +0,0 @@
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<ServerWebExchange, ServiceInstance> {
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);
}
}

View File

@@ -1,23 +0,0 @@
package com.gitee.sop.gatewaycommon.gateway.loadbalancer;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.netflix.loadbalancer.Server;
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
import java.util.Map;
/**
* @author tanghc
*/
public class NacosServerIntrospector extends DefaultServerIntrospector {
@Override
public Map<String, String> getMetadata(Server server) {
if (server instanceof NacosServer) {
NacosServer discoveryServer = (NacosServer)server;
return discoveryServer.getInstance().getMetadata();
} else {
return super.getMetadata(server);
}
}
}

View File

@@ -1,87 +0,0 @@
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.gitee.sop.gatewaycommon.util.LoadBalanceUtil;
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;
/**
* 重写负载均衡处理。
* 默认使用的是RibbonLoadBalancerClient类详见org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration#loadBalancerClient()
*
* @author tanghc
*/
public class SopLoadBalancerClient extends RibbonLoadBalancerClient implements ServerChooserContext<ServerWebExchange> {
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<Server> servers) {
Server server = LoadBalanceUtil.chooseByRoundRobin(serviceId, servers);
if (server == null) {
return null;
}
return new RibbonServer(
serviceId
, server
, isSecure(server, serviceId)
, serverIntrospector(serviceId).getMetadata(server)
);
}
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);
}
}

View File

@@ -0,0 +1,179 @@
package com.gitee.sop.gatewaycommon.loadbalancer;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import lombok.Data;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.*;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
@Data
public class GrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private static final Logger log = LoggerFactory.getLogger(GrayLoadBalancer.class);
private final String serviceId;
private AtomicInteger position; // 位置,下标
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
public GrayLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
this.serviceId = serviceId;
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
this.position = new AtomicInteger(new Random().nextInt(1000)); //随机进行设置一个值
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
// 提供备选的服务实例列表
ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
// 选择服务实例
return supplier.get(request).next().map((serviceInstances) -> this.processInstanceResponse(supplier, serviceInstances, request));
}
private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,
List<ServiceInstance> serviceInstances,
Request request) {
// 从备选的服务列表中选择一个具体的服务实例
Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances,
request);
if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
((SelectedInstanceCallback) supplier).selectedServiceInstance((ServiceInstance) serviceInstanceResponse.getServer());
}
return serviceInstanceResponse;
}
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances,
Request request) {
// 实例为空 首先进行实例判空
if (instances.isEmpty()) {
if (log.isWarnEnabled()) {
//判空后 给予警告
log.warn("No servers available for service: " + this.serviceId);
}
//返回响应
return new EmptyResponse();
} else {
// 存放预发服务器
List<ServiceInstance> preServers = new ArrayList<>(4);
// 存放灰度发布服务器
List<ServiceInstance> grayServers = new ArrayList<>(4);
// 存放非预发服务器
List<ServiceInstance> notPreServers = new ArrayList<>(4);
notPreServers.addAll(grayServers);
for (ServiceInstance instance : instances) {
// 获取实例metadata
Map<String, String> metadata = instance.getMetadata();
// 是否开启了预发模式
if (this.isPreServer(metadata)) {
preServers.add(instance);
} else if (this.isGrayServer(metadata)) {
grayServers.add(instance);
} else {
notPreServers.add(instance);
}
}
notPreServers.addAll(grayServers);
RequestDataContext context = (RequestDataContext) request.getContext();
ApiParam apiParam = new ApiParam();
apiParam.putAll(context.getClientRequest().getAttributes());
// 如果没有开启预发布服务和灰度发布,直接用默认的方式
if (preServers.isEmpty() && grayServers.isEmpty()) {
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
ServiceInstance instance = instances.get(pos % instances.size());
return new DefaultResponse(instance);
}
// 如果是从预发布域名访问过来,则认为是预发布请求,选出预发服务器
if (this.isRequestFromPreDomain(context.getClientRequest().getHeaders())) {
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
ServiceInstance instance = preServers.get(pos % instances.size());
return new DefaultResponse(instance);
}
// 如果是灰度请求,则认为是灰度用户,选出灰度服务器
if (apiParam.fetchGrayRequest()) {
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
ServiceInstance instance = grayServers.get(pos % instances.size());
return new DefaultResponse(instance);
}
return getInstanceResponse(instances);
}
}
/**
* 是否是预发布服务器
*
* @param metadata metadata
* @return true
*/
private boolean isPreServer(Map<String, String> metadata) {
return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_PRE_VALUE);
}
/**
* 是否是灰度发布服务器
*
* @param metadata metadata
* @return true
*/
private boolean isGrayServer(Map<String, String> metadata) {
return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_GRAY_VALUE);
}
/**
* 通过判断hostname来确定是否是预发布请求
*
* @param httpHeaders
* @return 返回true可以进入到预发环境
*/
boolean isRequestFromPreDomain(HttpHeaders httpHeaders) {
String domain = EnvironmentKeys.PRE_DOMAIN.getValue();
if (StringUtils.isEmpty(domain)) {
return false;
}
String[] domains = domain.split("\\,");
if (httpHeaders.getHost() != null) {
String host = httpHeaders.getHost().getHostName();
return ArrayUtils.contains(domains, host);
} else {
return false;
}
}
public Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
if (instances.isEmpty()) {
if (log.isWarnEnabled()) {
log.warn("No servers available for service: " + serviceId);
}
return new EmptyResponse();
}
// Do not move position when there is only 1 instance, especially some suppliers
// have already filtered instances
if (instances.size() == 1) {
return new DefaultResponse(instances.get(0));
}
// Ignore the sign bit, this allows pos to loop sequentially from 0 to
// Integer.MAX_VALUE
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
ServiceInstance instance = instances.get(pos % instances.size());
return new DefaultResponse(instance);
}
}

View File

@@ -0,0 +1,18 @@
package com.gitee.sop.gatewaycommon.loadbalancer;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration
public class GrayLoadBalancerConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> GrayLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new GrayLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}

View File

@@ -1,128 +0,0 @@
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<T, R> implements ServerChooserContext<T> {
private SpringClientFactory clientFactory;
/**
* 选择服务器
*
* @param serviceId serviceId仅gateway网关有作用
* @param exchange 请求上下文
* @param loadBalancer loadBalancer
* @param superChooser 父类默认的选择
* @param serverChooserFunction 执行选择操作
* @return 返回服务器实例没有选到则返回null
*/
public R choose(
String serviceId
, T exchange
, ILoadBalancer loadBalancer
, Supplier<R> superChooser
, Function<List<Server>, R> serverChooserFunction) {
// 获取所有服务实例
List<Server> servers = loadBalancer.getReachableServers();
// 存放预发服务器
List<Server> preServers = new ArrayList<>(4);
// 存放灰度发布服务器
List<Server> grayServers = new ArrayList<>(4);
// 存放非预发服务器
List<Server> notPreServers = new ArrayList<>(4);
for (Server server : servers) {
// 获取实例metadata
Map<String, String> 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);
}
// 到这里说明不能访问预发/灰度服务器,则需要路由到非预发服务器
// 注意这里允许走灰度服务器如果不允许走注释notPreServers.addAll(grayServers);这行
return serverChooserFunction.apply(notPreServers);
}
protected Map<String, String> 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<String, String> metadata) {
return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_PRE_VALUE);
}
/**
* 是否是灰度发布服务器
*
* @param metadata metadata
* @return true
*/
private boolean isGrayServer(Map<String, String> metadata) {
return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_GRAY_VALUE);
}
}

View File

@@ -1,35 +0,0 @@
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<T> extends ApiParamAware<T> {
/**
* 通过判断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.fetchGrayRequest();
}
String getHost(T t);
}

View File

@@ -1,7 +1,7 @@
package com.gitee.sop.gatewaycommon.manager;
import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Set;

View File

@@ -1,7 +1,7 @@
package com.gitee.sop.gatewaycommon.manager;
import com.gitee.sop.gatewaycommon.bean.ConfigLimitDto;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.Collections;

View File

@@ -1,9 +1,10 @@
package com.gitee.sop.gatewaycommon.route;
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
import com.gitee.sop.gatewaycommon.bean.SpringContext;
import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;

View File

@@ -7,7 +7,7 @@ import com.gitee.sop.gatewaycommon.bean.ServiceBeanInitializer;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpEntity;

View File

@@ -107,7 +107,7 @@ public class RequestUtil {
} catch (UnsupportedEncodingException e) {
log.error("字符集不支持", e);
}
return org.apache.commons.lang.StringUtils.join(list, "&");
return org.apache.commons.lang3.StringUtils.join(list, "&");
}
/**