Commit 8d46a54f by Nepxion

网关端使用Hystrix做线程模式的服务隔离时,实现服务灰度路由的功能

parent 83e61f4d
......@@ -15,6 +15,6 @@
@title Nepxion Discovery
@color 0a
call mvn clean deploy -DskipTests -e -P release -pl discovery-plugin-starter-eureka,discovery-plugin-starter-consul,discovery-plugin-starter-zookeeper,discovery-plugin-config-center-starter-apollo,discovery-plugin-config-center-starter-nacos,discovery-plugin-config-center-starter-redis,discovery-console-starter-apollo,discovery-console-starter-nacos,discovery-console-starter-redis,discovery-plugin-strategy-starter-service,discovery-plugin-strategy-starter-zuul,discovery-plugin-strategy-starter-gateway -am
call mvn clean deploy -DskipTests -e -P release -pl discovery-plugin-starter-eureka,discovery-plugin-starter-consul,discovery-plugin-starter-zookeeper,discovery-plugin-config-center-starter-apollo,discovery-plugin-config-center-starter-nacos,discovery-plugin-config-center-starter-redis,discovery-console-starter-apollo,discovery-console-starter-nacos,discovery-console-starter-redis,discovery-plugin-strategy-starter-service,discovery-plugin-strategy-starter-zuul,discovery-plugin-strategy-starter-gateway,discovery-plugin-strategy-starter-hystrix -am
pause
\ No newline at end of file
......@@ -9,19 +9,30 @@ package com.nepxion.discovery.plugin.strategy.gateway.adapter;
* @version 1.0
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.server.ServerWebExchange;
import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.plugin.strategy.adapter.AbstractDiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.gateway.context.GatewayStrategyContext;
import com.nepxion.discovery.plugin.strategy.gateway.context.GatewayStrategyContextHolder;
import com.netflix.loadbalancer.Server;
public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter {
@Override
protected String getVersionValue() {
GatewayStrategyContext context = GatewayStrategyContext.getCurrentContext();
private static final Logger LOG = LoggerFactory.getLogger(DefaultDiscoveryEnabledAdapter.class);
@Autowired
private GatewayStrategyContextHolder gatewayStrategyContextHolder;
ServerWebExchange exchange = context.getExchange();
@Override
protected String getVersionValue(Server server) {
ServerWebExchange exchange = gatewayStrategyContextHolder.getExchange();
if (exchange == null) {
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
LOG.warn("The ServerWebExchange object is null, ignore to do version filter for service={}...", serviceId);
return null;
}
......@@ -29,11 +40,13 @@ public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdap
}
@Override
protected String getRegionValue() {
GatewayStrategyContext context = GatewayStrategyContext.getCurrentContext();
ServerWebExchange exchange = context.getExchange();
protected String getRegionValue(Server server) {
ServerWebExchange exchange = gatewayStrategyContextHolder.getExchange();
if (exchange == null) {
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
LOG.warn("The ServerWebExchange object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
......
......@@ -18,6 +18,7 @@ import org.springframework.context.annotation.Configuration;
import com.nepxion.discovery.plugin.strategy.adapter.DiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.constant.StrategyConstant;
import com.nepxion.discovery.plugin.strategy.gateway.adapter.DefaultDiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.gateway.context.GatewayStrategyContextHolder;
import com.nepxion.discovery.plugin.strategy.gateway.filter.GatewayStrategyFilter;
@Configuration
......@@ -30,6 +31,11 @@ public class GatewayStrategyAutoConfiguration {
}
@Bean
public GatewayStrategyContextHolder gatewayStrategyContextHolder() {
return new GatewayStrategyContextHolder();
}
@Bean
public DiscoveryEnabledAdapter discoveryEnabledAdapter() {
return new DefaultDiscoveryEnabledAdapter();
}
......
package com.nepxion.discovery.plugin.strategy.gateway.context;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.web.server.ServerWebExchange;
import com.nepxion.discovery.plugin.strategy.constant.StrategyConstant;
public class GatewayStrategyContextHolder {
@Autowired
private ConfigurableEnvironment environment;
public ServerWebExchange getExchange() {
Boolean hystrixThreadlocalSupported = environment.getProperty(StrategyConstant.SPRING_APPLICATION_STRATEGY_HYSTRIX_THREADLOCAL_SUPPORTED, Boolean.class, Boolean.FALSE);
if (hystrixThreadlocalSupported) {
// Spring Cloud Gateway网关端使用Hystrix做线程模式的服务隔离时,实现服务灰度路由的功能
return GatewayStrategyContext.getCurrentContext().getExchange();
} else {
return GatewayStrategyContext.getCurrentContext().getExchange();
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<artifactId>discovery-plugin-strategy-starter-hystrix</artifactId>
<name>Nepxion Discovery Plugin Strategy Starter Hystrix</name>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
<description>Nepxion Discovery is an enhancement for Spring Cloud Discovery</description>
<url>http://www.nepxion.com</url>
<parent>
<groupId>com.nepxion</groupId>
<artifactId>discovery</artifactId>
<version>4.7.12</version>
</parent>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>discovery-plugin-strategy</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.hystrix.configuration;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @author Hao Wang
* @version 1.0
*/
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.nepxion.discovery.plugin.strategy.constant.StrategyConstant;
import com.nepxion.discovery.plugin.strategy.hystrix.context.HystrixContextConcurrencyStrategy;
import com.netflix.hystrix.Hystrix;
@Configuration
@ConditionalOnClass(Hystrix.class)
@ConditionalOnProperty(value = StrategyConstant.SPRING_APPLICATION_STRATEGY_HYSTRIX_THREADLOCAL_SUPPORTED, matchIfMissing = false)
public class HystrixStrategyAutoConfiguration {
@Bean
public HystrixContextConcurrencyStrategy hystrixContextConcurrencyStrategy() {
return new HystrixContextConcurrencyStrategy();
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.hystrix.context;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @author Hao Wang
* @version 1.0
*/
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import com.nepxion.discovery.plugin.strategy.wrapper.CallableWrapper;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
// 使用线程隔离模式时,无法获取threadLocal中信息,自定义并发策略解决
public class HystrixContextConcurrencyStrategy extends HystrixConcurrencyStrategy {
@Autowired
private CallableWrapper wrapper;
private HystrixConcurrencyStrategy delegate;
public HystrixContextConcurrencyStrategy() {
// HystrixPlugins只能注册一次策略,保留原对象
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
// Keeps references of existing Hystrix plugins.
HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook();
HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();
HystrixPlugins.reset();
// Registers existing plugins excepts the Concurrent Strategy plugin.
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
}
@Override
public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
return delegate.getBlockingQueue(maxQueueSize);
}
@Override
public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
return delegate.getRequestVariable(rv);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixProperty<Integer> corePoolSize, HystrixProperty<Integer> maximumPoolSize, HystrixProperty<Integer> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
return delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {
return delegate.getThreadPool(threadPoolKey, threadPoolProperties);
}
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
return wrapper.wrapCallable(callable);
}
}
\ No newline at end of file
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.nepxion.discovery.plugin.strategy.hystrix.configuration.HystrixStrategyAutoConfiguration
\ No newline at end of file
......@@ -9,17 +9,26 @@ package com.nepxion.discovery.plugin.strategy.service.adapter;
* @version 1.0
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.plugin.strategy.adapter.AbstractDiscoveryEnabledAdapter;
import com.netflix.loadbalancer.Server;
public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(DefaultDiscoveryEnabledAdapter.class);
@Override
protected String getVersionValue() {
protected String getVersionValue(Server server) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
LOG.warn("The ServletRequestAttributes object is null, ignore to do version filter for service={}...", serviceId);
return null;
}
......@@ -27,9 +36,13 @@ public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdap
}
@Override
protected String getRegionValue() {
protected String getRegionValue(Server server) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
LOG.warn("The ServletRequestAttributes object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
......
......@@ -42,7 +42,6 @@ public class FeignStrategyInterceptor implements RequestInterceptor {
}
HttpServletRequest previousRequest = attributes.getRequest();
Enumeration<String> headerNames = previousRequest.getHeaderNames();
if (headerNames == null) {
return;
......
......@@ -45,14 +45,12 @@ public class RestTemplateStrategyInterceptor implements ClientHttpRequestInterce
}
HttpServletRequest previousRequest = attributes.getRequest();
Enumeration<String> headerNames = previousRequest.getHeaderNames();
if (headerNames == null) {
return execution.execute(request, body);
}
HttpHeaders headers = request.getHeaders();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String header = previousRequest.getHeader(headerName);
......
......@@ -9,22 +9,48 @@ package com.nepxion.discovery.plugin.strategy.zuul.adapter;
* @version 1.0
*/
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.plugin.strategy.adapter.AbstractDiscoveryEnabledAdapter;
import com.netflix.zuul.context.RequestContext;
import com.nepxion.discovery.plugin.strategy.zuul.context.ZuulStrategyContextHolder;
import com.netflix.loadbalancer.Server;
public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(DefaultDiscoveryEnabledAdapter.class);
@Autowired
private ZuulStrategyContextHolder zuulStrategyContextHolder;
@Override
protected String getVersionValue() {
RequestContext context = RequestContext.getCurrentContext();
protected String getVersionValue(Server server) {
HttpServletRequest request = zuulStrategyContextHolder.getRequest();
if (request == null) {
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
return context.getRequest().getHeader(DiscoveryConstant.VERSION);
LOG.warn("The HttpServletRequest object is null, ignore to do version filter for service={}...", serviceId);
return null;
}
return request.getHeader(DiscoveryConstant.VERSION);
}
@Override
protected String getRegionValue() {
RequestContext context = RequestContext.getCurrentContext();
protected String getRegionValue(Server server) {
HttpServletRequest request = zuulStrategyContextHolder.getRequest();
if (request == null) {
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
LOG.warn("The HttpServletRequest object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
return context.getRequest().getHeader(DiscoveryConstant.REGION);
return request.getHeader(DiscoveryConstant.REGION);
}
}
\ No newline at end of file
......@@ -17,7 +17,10 @@ import org.springframework.context.annotation.Configuration;
import com.nepxion.discovery.plugin.strategy.adapter.DiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.constant.StrategyConstant;
import com.nepxion.discovery.plugin.strategy.wrapper.CallableWrapper;
import com.nepxion.discovery.plugin.strategy.zuul.adapter.DefaultDiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.zuul.context.ZuulStrategyContextHolder;
import com.nepxion.discovery.plugin.strategy.zuul.wrapper.DefaultCallableWrapper;
@Configuration
@AutoConfigureBefore(RibbonClientConfiguration.class)
......@@ -27,4 +30,15 @@ public class ZuulStrategyAutoConfiguration {
public DiscoveryEnabledAdapter discoveryEnabledAdapter() {
return new DefaultDiscoveryEnabledAdapter();
}
@Bean
public ZuulStrategyContextHolder zuulStrategyContextHolder() {
return new ZuulStrategyContextHolder();
}
@Bean
@ConditionalOnProperty(value = StrategyConstant.SPRING_APPLICATION_STRATEGY_HYSTRIX_THREADLOCAL_SUPPORTED, matchIfMissing = false)
public CallableWrapper callableWrapper() {
return new DefaultCallableWrapper();
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.zuul.context;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @author Hao Wang
* @version 1.0
*/
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class ZuulStrategyContext {
private static final ThreadLocal<ZuulStrategyContext> THREAD_LOCAL = new InheritableThreadLocal<ZuulStrategyContext>() {
@Override
protected ZuulStrategyContext initialValue() {
return new ZuulStrategyContext();
}
};
public static ZuulStrategyContext getCurrentContext() {
return THREAD_LOCAL.get();
}
public static void clearCurrentContext() {
THREAD_LOCAL.remove();
}
private HttpServletRequest request;
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public boolean equals(Object object) {
return EqualsBuilder.reflectionEquals(this, object);
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.zuul.context;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.ConfigurableEnvironment;
import com.nepxion.discovery.plugin.strategy.constant.StrategyConstant;
import com.netflix.zuul.context.RequestContext;
public class ZuulStrategyContextHolder {
@Autowired
private ConfigurableEnvironment environment;
public HttpServletRequest getRequest() {
Boolean hystrixThreadlocalSupported = environment.getProperty(StrategyConstant.SPRING_APPLICATION_STRATEGY_HYSTRIX_THREADLOCAL_SUPPORTED, Boolean.class, Boolean.FALSE);
if (hystrixThreadlocalSupported) {
return ZuulStrategyContext.getCurrentContext().getRequest();
} else {
return RequestContext.getCurrentContext().getRequest();
}
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.zuul.wrapper;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @author Hao Wang
* @version 1.0
*/
import java.util.concurrent.Callable;
import javax.servlet.http.HttpServletRequest;
import com.nepxion.discovery.plugin.strategy.wrapper.CallableWrapper;
import com.nepxion.discovery.plugin.strategy.zuul.context.ZuulStrategyContext;
import com.netflix.zuul.context.RequestContext;
public class DefaultCallableWrapper implements CallableWrapper {
@Override
public <T> Callable<T> wrapCallable(Callable<T> delegate) {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
return new Callable<T>() {
@Override
public T call() throws Exception {
try {
ZuulStrategyContext.getCurrentContext().setRequest(request);
return delegate.call();
} finally {
ZuulStrategyContext.clearCurrentContext();
}
}
};
}
}
\ No newline at end of file
......@@ -39,7 +39,7 @@ public abstract class AbstractDiscoveryEnabledAdapter implements DiscoveryEnable
@SuppressWarnings("unchecked")
private boolean applyVersion(Server server, Map<String, String> metadata) {
String versionValue = getVersionValue();
String versionValue = getVersionValue(server);
if (StringUtils.isEmpty(versionValue)) {
return true;
}
......@@ -64,7 +64,7 @@ public abstract class AbstractDiscoveryEnabledAdapter implements DiscoveryEnable
}
private boolean applyRegion(Server server, Map<String, String> metadata) {
String regionValue = getRegionValue();
String regionValue = getRegionValue(server);
if (StringUtils.isEmpty(regionValue)) {
return true;
}
......@@ -89,7 +89,7 @@ public abstract class AbstractDiscoveryEnabledAdapter implements DiscoveryEnable
return discoveryEnabledStrategy.apply(server, metadata);
}
protected abstract String getVersionValue();
protected abstract String getVersionValue(Server server);
protected abstract String getRegionValue();
protected abstract String getRegionValue(Server server);
}
\ No newline at end of file
......@@ -12,4 +12,5 @@ package com.nepxion.discovery.plugin.strategy.constant;
public class StrategyConstant {
public static final String SPRING_APPLICATION_STRATEGY_CONTROL_ENABLED = "spring.application.strategy.control.enabled";
public static final String SPRING_APPLICATION_STRATEGY_ZONE_AVOIDANCE_RULE_ENABLED = "spring.application.strategy.zone.avoidance.rule.enabled";
public static final String SPRING_APPLICATION_STRATEGY_HYSTRIX_THREADLOCAL_SUPPORTED = "spring.application.strategy.hystrix.threadlocal.supported";
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.wrapper;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @author Hao Wang
* @version 1.0
*/
import java.util.concurrent.Callable;
public interface CallableWrapper {
<T> Callable<T> wrapCallable(Callable<T> delegate);
}
\ No newline at end of file
......@@ -14,15 +14,20 @@ import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.server.ServerWebExchange;
import com.nepxion.discovery.plugin.strategy.adapter.DiscoveryEnabledStrategy;
import com.nepxion.discovery.plugin.strategy.gateway.context.GatewayStrategyContext;
import com.nepxion.discovery.plugin.strategy.gateway.context.GatewayStrategyContextHolder;
import com.netflix.loadbalancer.Server;
// 实现了组合策略,版本路由策略+区域路由策略+自定义策略
public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledStrategy.class);
@Autowired
private GatewayStrategyContextHolder gatewayStrategyContextHolder;
@Override
public boolean apply(Server server, Map<String, String> metadata) {
// 对Rest调用传来的Header参数(例如Token)做策略
......@@ -31,13 +36,17 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
// 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例
private boolean applyFromHeader(Server server, Map<String, String> metadata) {
GatewayStrategyContext context = GatewayStrategyContext.getCurrentContext();
String token = context.getExchange().getRequest().getHeaders().getFirst("token");
// String value = context.getExchange().getRequest().getQueryParams().getFirst("value");
ServerWebExchange exchange = gatewayStrategyContextHolder.getExchange();
if (exchange == null) {
return true;
}
String token = exchange.getRequest().getHeaders().getFirst("token");
// String value = exchange.getRequest().getQueryParams().getFirst("value");
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
LOG.info("Gateway端负载均衡用户定制触发:serviceId={}, host={}, metadata={}, context={}", serviceId, server.toString(), metadata, context);
LOG.info("Gateway端负载均衡用户定制触发:serviceId={}, host={}, metadata={}", serviceId, server.toString(), metadata);
String filterToken = "abc";
if (StringUtils.isNotEmpty(token) && token.contains(filterToken)) {
......
......@@ -72,6 +72,12 @@
<artifactId>discovery-plugin-strategy-starter-zuul</artifactId>
</dependency>
<!-- Used for zuul hystrix thread isolation -->
<dependency>
<groupId>com.nepxion</groupId>
<artifactId>discovery-plugin-strategy-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
......
......@@ -11,18 +11,24 @@ package com.nepxion.discovery.plugin.example.zuul.impl;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.nepxion.discovery.plugin.strategy.adapter.DiscoveryEnabledStrategy;
import com.nepxion.discovery.plugin.strategy.zuul.context.ZuulStrategyContextHolder;
import com.netflix.loadbalancer.Server;
import com.netflix.zuul.context.RequestContext;
// 实现了组合策略,版本路由策略+区域路由策略+自定义策略
public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledStrategy.class);
@Autowired
private ZuulStrategyContextHolder zuulStrategyContextHolder;
@Override
public boolean apply(Server server, Map<String, String> metadata) {
// 对Rest调用传来的Header参数(例如Token)做策略
......@@ -31,13 +37,17 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
// 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例
private boolean applyFromHeader(Server server, Map<String, String> metadata) {
RequestContext context = RequestContext.getCurrentContext();
String token = context.getRequest().getHeader("token");
// String value = context.getRequest().getParameter("value");
HttpServletRequest request = zuulStrategyContextHolder.getRequest();
if (request == null) {
return true;
}
String token = request.getHeader("token");
// String value = request.getParameter("value");
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
LOG.info("Zuul端负载均衡用户定制触发:serviceId={}, host={}, metadata={}, context={}", serviceId, server.toString(), metadata, context);
LOG.info("Zuul端负载均衡用户定制触发:serviceId={}, host={}, metadata={}", serviceId, server.toString(), metadata);
String filterToken = "abc";
if (StringUtils.isNotEmpty(token) && token.contains(filterToken)) {
......
......@@ -71,4 +71,7 @@ spring.boot.admin.url=http://localhost:5555
# 开启和关闭策略扩展功能的控制。一旦关闭,用户自定义和编程灰度路由策略功能将失效。缺失则默认为true
# spring.application.strategy.control.enabled=true
# 开启和关闭Ribbon默认的ZoneAvoidanceRule负载均衡策略。一旦关闭,则使用RoundRobin简单轮询负载均衡策略。缺失则默认为true
# spring.application.strategy.zone.avoidance.rule.enabled=true
\ No newline at end of file
# spring.application.strategy.zone.avoidance.rule.enabled=true
# 开启Zuul网关上实现Hystrix线程隔离模式做服务隔离时,必须把spring.application.strategy.hystrix.threadlocal.supported设置为true,同时要引入discovery-plugin-strategy-starter-hystrix包,否则线程切换时会发生ThreadLocal上下文对象丢失
# zuul.ribbon-isolation-strategy=thread
# spring.application.strategy.hystrix.threadlocal.supported=true
\ No newline at end of file
......@@ -31,6 +31,7 @@
<module>discovery-plugin-strategy-starter-service</module>
<module>discovery-plugin-strategy-starter-zuul</module>
<module>discovery-plugin-strategy-starter-gateway</module>
<module>discovery-plugin-strategy-starter-hystrix</module>
<module>discovery-console</module>
<module>discovery-console-starter-apollo</module>
<module>discovery-console-starter-nacos</module>
......@@ -187,6 +188,12 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>discovery-plugin-strategy-starter-hystrix</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>discovery-console</artifactId>
<version>${project.version}</version>
</dependency>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment