diff --git a/pom.xml b/pom.xml
index b4a9829a6..5f3320a22 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,6 @@
yudao-module-system
yudao-module-infra
- yudao-spring-boot-starter-env
diff --git a/yudao-framework/pom.xml b/yudao-framework/pom.xml
index 422a432cb..cd703719c 100644
--- a/yudao-framework/pom.xml
+++ b/yudao-framework/pom.xml
@@ -11,6 +11,7 @@
pom
yudao-common
+ yudao-spring-boot-starter-env
yudao-spring-boot-starter-banner
yudao-spring-boot-starter-mybatis
yudao-spring-boot-starter-redis
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/grey/GrayLoadBalancer.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/grey/GrayLoadBalancer.java
index 1ef2d01ab..452e5fdb0 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/grey/GrayLoadBalancer.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/grey/GrayLoadBalancer.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.gateway.filter.grey;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.gateway.util.EnvUtils;
import com.alibaba.cloud.nacos.balancer.NacosBalancer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -62,7 +63,7 @@ public class GrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {
return new EmptyResponse();
}
- // 筛选满足条件的实例列表
+ // 筛选满足 version 条件的实例列表
String version = headers.getFirst(VERSION);
List chooseInstances;
if (StrUtil.isEmpty(version)) {
@@ -70,12 +71,41 @@ public class GrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {
} else {
chooseInstances = CollectionUtils.filterList(instances, instance -> version.equals(instance.getMetadata().get("version")));
if (CollUtil.isEmpty(chooseInstances)) {
- log.warn("[getInstanceResponse][serviceId({}) 没有满足版本的服务实例列表,直接使用所有服务实例列表]", serviceId);
+ log.warn("[getInstanceResponse][serviceId({}) 没有满足版本({})的服务实例列表,直接使用所有服务实例列表]", serviceId, version);
chooseInstances = instances;
}
}
+ // 基于 tag 过滤实例列表
+ chooseInstances = filterTagServiceInstances(chooseInstances, headers);
+
// 随机 + 权重获取实例列表 TODO 芋艿:目前直接使用 Nacos 提供的方法,如果替换注册中心,需要重新失败该方法
return new DefaultResponse(NacosBalancer.getHostByRandomWeight3(chooseInstances));
}
+
+ /**
+ * 基于 tag 请求头,过滤匹配 tag 的服务实例列表
+ *
+ * copy from EnvLoadBalancerClient
+ *
+ * @param instances 服务实例列表
+ * @param headers 请求头
+ * @return 服务实例列表
+ */
+ private List filterTagServiceInstances(List instances, HttpHeaders headers) {
+ // 情况一,没有 tag 时,直接返回
+ String tag = EnvUtils.getTag(headers);
+ if (StrUtil.isEmpty(tag)) {
+ return instances;
+ }
+
+ // 情况二,有 tag 时,使用 tag 匹配服务实例
+ List chooseInstances = CollectionUtils.filterList(instances, instance -> tag.equals(EnvUtils.getTag(instance)));
+ if (CollUtil.isEmpty(chooseInstances)) {
+ log.warn("[filterTagServiceInstances][serviceId({}) 没有满足 tag({}) 的服务实例列表,直接使用所有服务实例列表]", serviceId, tag);
+ chooseInstances = instances;
+ }
+ return chooseInstances;
+ }
+
}
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/EnvUtils.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/EnvUtils.java
new file mode 100644
index 000000000..5f690460b
--- /dev/null
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/EnvUtils.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.gateway.util;
+
+import cn.hutool.core.net.NetUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.http.HttpHeaders;
+
+import java.util.Objects;
+
+/**
+ * 环境 Utils
+ *
+ * copy from yudao-spring-boot-starter-env 的 EnvUtils 类
+ *
+ * @author 芋道源码
+ */
+public class EnvUtils {
+
+ private static final String HEADER_TAG = "tag";
+
+ public static final String HOST_NAME_VALUE = "${HOSTNAME}";
+
+ public static String getTag(HttpHeaders headers) {
+ String tag = headers.getFirst(HEADER_TAG);
+ // 如果请求的是 "${HOSTNAME}",则解析成对应的本地主机名
+ // 目的:特殊逻辑,解决 IDEA Rest Client 不支持环境变量的读取,所以就服务器来做
+ return Objects.equals(tag, HOST_NAME_VALUE) ? getHostName() : tag;
+ }
+
+ public static String getTag(ServiceInstance instance) {
+ return instance.getMetadata().get(HEADER_TAG);
+ }
+
+ public static String getHostName() {
+ return StrUtil.blankToDefault(NetUtil.getLocalHostName(), IdUtil.fastSimpleUUID());
+ }
+
+}
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/WebFrameworkUtils.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/WebFrameworkUtils.java
index 031c9a8c1..0553cc3f6 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/WebFrameworkUtils.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/WebFrameworkUtils.java
@@ -26,9 +26,10 @@ import reactor.core.publisher.Mono;
@Slf4j
public class WebFrameworkUtils {
- @SuppressWarnings("UastIncorrectHttpHeaderInspection")
private static final String HEADER_TENANT_ID = "tenant-id";
+ private static final String HEADER_TAG = "tag";
+
private WebFrameworkUtils() {}
/**