Commit 2fac9dae by Nepxion

通过Rest方式实时版本路由功能

parent 4d361e97
...@@ -42,7 +42,9 @@ public abstract class LocalConfigLoader implements ConfigLoader { ...@@ -42,7 +42,9 @@ public abstract class LocalConfigLoader implements ConfigLoader {
return IOUtils.toString(inputStream, DiscoveryConstant.ENCODING_UTF_8); return IOUtils.toString(inputStream, DiscoveryConstant.ENCODING_UTF_8);
} catch (Exception e) { } catch (Exception e) {
throw e; LOG.warn(e.getMessage() + ", ignore to load...");
return null;
} finally { } finally {
if (inputStream != null) { if (inputStream != null) {
IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(inputStream);
......
package com.nepxion.discovery.plugin.strategy.extension.gateway.impl;
/**
* <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 java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.common.util.JsonUtil;
import com.nepxion.discovery.plugin.strategy.discovery.DiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.extension.gateway.context.GatewayStrategyContext;
import com.netflix.loadbalancer.Server;
public class VersionDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter {
@SuppressWarnings("unchecked")
@Override
public boolean apply(Server server, Map<String, String> metadata) {
GatewayStrategyContext context = GatewayStrategyContext.getCurrentContext();
String versionJson = context.getExchange().getRequest().getHeaders().getFirst(DiscoveryConstant.VERSION);
if (StringUtils.isEmpty(versionJson)) {
return true;
}
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
String version = metadata.get(DiscoveryConstant.VERSION);
if (StringUtils.isEmpty(version)) {
return true;
}
Map<String, String> versionMap = JsonUtil.fromJson(versionJson, Map.class);
String versions = versionMap.get(serviceId);
if (StringUtils.isEmpty(versions)) {
return true;
}
if (versions.contains(version)) {
return true;
}
return false;
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.service.impl;
/**
* <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 java.util.Map;
import org.apache.commons.lang3.StringUtils;
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.common.util.JsonUtil;
import com.nepxion.discovery.plugin.strategy.discovery.DiscoveryEnabledAdapter;
import com.netflix.loadbalancer.Server;
public class VersionDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter {
@SuppressWarnings("unchecked")
@Override
public boolean apply(Server server, Map<String, String> metadata) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return true;
}
String versionJson = attributes.getRequest().getHeader(DiscoveryConstant.VERSION);
if (StringUtils.isEmpty(versionJson)) {
return true;
}
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
String version = metadata.get(DiscoveryConstant.VERSION);
if (StringUtils.isEmpty(version)) {
return true;
}
Map<String, String> versionMap = JsonUtil.fromJson(versionJson, Map.class);
String versions = versionMap.get(serviceId);
if (StringUtils.isEmpty(versions)) {
return true;
}
if (versions.contains(version)) {
return true;
}
return false;
}
}
\ No newline at end of file
...@@ -19,5 +19,10 @@ ...@@ -19,5 +19,10 @@
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>discovery-plugin-strategy</artifactId> <artifactId>discovery-plugin-strategy</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.zuul.impl;
/**
* <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 java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.common.util.JsonUtil;
import com.nepxion.discovery.plugin.strategy.discovery.DiscoveryEnabledAdapter;
import com.netflix.loadbalancer.Server;
import com.netflix.zuul.context.RequestContext;
public class VersionDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter {
@SuppressWarnings("unchecked")
@Override
public boolean apply(Server server, Map<String, String> metadata) {
RequestContext context = RequestContext.getCurrentContext();
String versionJson = context.getRequest().getHeader(DiscoveryConstant.VERSION);
if (StringUtils.isEmpty(versionJson)) {
return true;
}
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
String version = metadata.get(DiscoveryConstant.VERSION);
if (StringUtils.isEmpty(version)) {
return true;
}
Map<String, String> versionMap = JsonUtil.fromJson(versionJson, Map.class);
String versions = versionMap.get(serviceId);
if (StringUtils.isEmpty(versions)) {
return true;
}
if (versions.contains(version)) {
return true;
}
return false;
}
}
\ No newline at end of file
...@@ -72,11 +72,6 @@ ...@@ -72,11 +72,6 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId> <groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId> <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency> </dependency>
......
...@@ -15,23 +15,33 @@ import org.apache.commons.lang3.StringUtils; ...@@ -15,23 +15,33 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.nepxion.discovery.plugin.strategy.discovery.DiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.extension.gateway.context.GatewayStrategyContext; import com.nepxion.discovery.plugin.strategy.extension.gateway.context.GatewayStrategyContext;
import com.nepxion.discovery.plugin.strategy.extension.gateway.impl.VersionDiscoveryEnabledAdapter;
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
public class MyDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter { // 实现了组合策略,版本路由策略+自定义策略
// 如果不想要版本路由策略,请直接implements DiscoveryEnabledAdapter,实现自定义策略
public class MyDiscoveryEnabledAdapter extends VersionDiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledAdapter.class); private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledAdapter.class);
// 根据外部传来的Header参数(例如Token),选取执行调用请求的服务实例
@Override @Override
public boolean apply(Server server, Map<String, String> metadata) { public boolean apply(Server server, Map<String, String> metadata) {
// 1.对Rest调用传来的Header的路由Version做策略。注意这个Version不是灰度发布的Version
boolean enabled = super.apply(server, metadata);
if (!enabled) {
return false;
}
// 2.对Rest调用传来的Header参数(例如Token)做策略
return applyFromHeader(server, metadata);
}
// 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例
private boolean applyFromHeader(Server server, Map<String, String> metadata) {
GatewayStrategyContext context = GatewayStrategyContext.getCurrentContext(); GatewayStrategyContext context = GatewayStrategyContext.getCurrentContext();
String token = context.getExchange().getRequest().getHeaders().getFirst("token"); String token = context.getExchange().getRequest().getHeaders().getFirst("token");
// String value = context.getExchange().getRequest().getQueryParams().getFirst("value"); // String value = context.getExchange().getRequest().getQueryParams().getFirst("value");
// 执行完后,请手工清除上下文对象,否则可能会造成内存泄露
GatewayStrategyContext.clearCurrentContext();
String serviceId = server.getMetaInfo().getAppName().toLowerCase(); String serviceId = server.getMetaInfo().getAppName().toLowerCase();
LOG.info("Gateway端负载均衡用户定制触发:serviceId={}, host={}, metadata={}, context={}", serviceId, server.toString(), metadata, context); LOG.info("Gateway端负载均衡用户定制触发:serviceId={}, host={}, metadata={}, context={}", serviceId, server.toString(), metadata, context);
......
...@@ -18,24 +18,35 @@ import org.springframework.web.context.request.RequestContextHolder; ...@@ -18,24 +18,35 @@ import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import com.nepxion.discovery.common.constant.DiscoveryConstant; import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.plugin.strategy.discovery.DiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.extension.service.constant.ServiceStrategyConstant; import com.nepxion.discovery.plugin.strategy.extension.service.constant.ServiceStrategyConstant;
import com.nepxion.discovery.plugin.strategy.extension.service.context.ServiceStrategyContext; import com.nepxion.discovery.plugin.strategy.extension.service.context.ServiceStrategyContext;
import com.nepxion.discovery.plugin.strategy.extension.service.impl.VersionDiscoveryEnabledAdapter;
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
public class MyDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter { // 实现了组合策略,版本路由策略+自定义策略
// 如果不想要版本路由策略,请直接implements DiscoveryEnabledAdapter,实现自定义策略
public class MyDiscoveryEnabledAdapter extends VersionDiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledAdapter.class); private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledAdapter.class);
@Override @Override
public boolean apply(Server server, Map<String, String> metadata) { public boolean apply(Server server, Map<String, String> metadata) {
if (applyFromHeader(server, metadata)) { // 1.对Rest调用传来的Header的路由Version做策略。注意这个Version不是灰度发布的Version
return applyFromMethd(server, metadata); boolean enabled = super.apply(server, metadata);
} else { if (!enabled) {
return false;
}
// 2.对Rest调用传来的Header参数(例如Token)做策略
enabled = applyFromHeader(server, metadata);
if (!enabled) {
return false; return false;
} }
// 3.对RPC调用传来的方法参数做策略
return applyFromMethd(server, metadata);
} }
// 方式1,根据外部传来的Header参数(例如Token),选取执行调用请求的服务实例 // 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例
private boolean applyFromHeader(Server server, Map<String, String> metadata) { private boolean applyFromHeader(Server server, Map<String, String> metadata) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) { if (attributes == null) {
...@@ -60,7 +71,7 @@ public class MyDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter { ...@@ -60,7 +71,7 @@ public class MyDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter {
return true; return true;
} }
// 方式2,根据下游服务传来的方法参数(例如接口名、方法名、参数名或参数值等),选取执行调用请求的服务实例 // 根据RPC调用传来的方法参数(例如接口名、方法名、参数名或参数值等),选取执行调用请求的服务实例
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private boolean applyFromMethd(Server server, Map<String, String> metadata) { private boolean applyFromMethd(Server server, Map<String, String> metadata) {
ServiceStrategyContext context = ServiceStrategyContext.getCurrentContext(); ServiceStrategyContext context = ServiceStrategyContext.getCurrentContext();
......
...@@ -68,4 +68,4 @@ spring.boot.admin.url=http://localhost:5555 ...@@ -68,4 +68,4 @@ spring.boot.admin.url=http://localhost:5555
# 用户自定义和编程灰度路由策略的时候,需要指定对业务Controller类的扫描路径,以便传递上下文对象。该项配置只对服务有效,对网关无效。缺失则默认关闭改功能 # 用户自定义和编程灰度路由策略的时候,需要指定对业务Controller类的扫描路径,以便传递上下文对象。该项配置只对服务有效,对网关无效。缺失则默认关闭改功能
spring.application.strategy.scan.packages=com.nepxion.discovery.plugin.example.service.feign spring.application.strategy.scan.packages=com.nepxion.discovery.plugin.example.service.feign
# 用户自定义和编程灰度路由策略的时候,如果采用Feign进行Rest调用,需要把来自网关的某些Header参数传递到服务里,如果多个用“;”分隔,不允许出现空格。该项配置只对服务有效,对网关无效。缺失则默认关闭改功能 # 用户自定义和编程灰度路由策略的时候,如果采用Feign进行Rest调用,需要把来自网关的某些Header参数传递到服务里,如果多个用“;”分隔,不允许出现空格。该项配置只对服务有效,对网关无效。缺失则默认关闭改功能
spring.application.strategy.feign.headers=token spring.application.strategy.feign.headers=version;token
\ No newline at end of file \ No newline at end of file
...@@ -72,11 +72,6 @@ ...@@ -72,11 +72,6 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId> <groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId> <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency> </dependency>
......
...@@ -15,16 +15,29 @@ import org.apache.commons.lang3.StringUtils; ...@@ -15,16 +15,29 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.nepxion.discovery.plugin.strategy.discovery.DiscoveryEnabledAdapter; import com.nepxion.discovery.plugin.strategy.extension.zuul.impl.VersionDiscoveryEnabledAdapter;
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.context.RequestContext;
public class MyDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter { // 实现了组合策略,版本路由策略+自定义策略
// 如果不想要版本路由策略,请直接implements DiscoveryEnabledAdapter,实现自定义策略
public class MyDiscoveryEnabledAdapter extends VersionDiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledAdapter.class); private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledAdapter.class);
// 根据外部传来的Header参数(例如Token),选取执行调用请求的服务实例
@Override @Override
public boolean apply(Server server, Map<String, String> metadata) { public boolean apply(Server server, Map<String, String> metadata) {
// 1.对Rest调用传来的Header的路由Version做策略。注意这个Version不是灰度发布的Version
boolean enabled = super.apply(server, metadata);
if (!enabled) {
return false;
}
// 2.对Rest调用传来的Header参数(例如Token)做策略
return applyFromHeader(server, metadata);
}
// 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例
private boolean applyFromHeader(Server server, Map<String, String> metadata) {
RequestContext context = RequestContext.getCurrentContext(); RequestContext context = RequestContext.getCurrentContext();
String token = context.getRequest().getHeader("token"); String token = context.getRequest().getHeader("token");
// String value = context.getRequest().getParameter("value"); // String value = context.getRequest().getParameter("value");
......
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