diff --git a/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/ZdxtGatewayApplication.java b/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/ZdxtGatewayApplication.java
index 9c7082bb..1496d095 100644
--- a/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/ZdxtGatewayApplication.java
+++ b/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/ZdxtGatewayApplication.java
@@ -4,6 +4,7 @@ import com.zdxt.gateway.webserver.config.LoadBalancerConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
+import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
/**
* API网关启动类
@@ -11,7 +12,11 @@ import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
* @author zdxt
*/
@SpringBootApplication
-@LoadBalancerClient(name = "backend-service", configuration = LoadBalancerConfig.class)
+@LoadBalancerClients({
+ @LoadBalancerClient(name = "ent-ep-service", configuration = LoadBalancerConfig.class),
+ @LoadBalancerClient(name = "enf-ep-service", configuration = LoadBalancerConfig.class),
+ @LoadBalancerClient(name = "sup-ep-service", configuration = LoadBalancerConfig.class)
+})
public class ZdxtGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ZdxtGatewayApplication.class, args);
diff --git a/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/config/LoadBalancerConfig.java b/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/config/LoadBalancerConfig.java
index 1db755ef..1245116b 100644
--- a/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/config/LoadBalancerConfig.java
+++ b/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/config/LoadBalancerConfig.java
@@ -1,7 +1,7 @@
package com.zdxt.gateway.webserver.config;
import org.springframework.cloud.client.ServiceInstance;
-import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
+import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryProperties;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
@@ -9,10 +9,18 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
/**
- * 负载均衡配置 - 随机策略
+ * 负载均衡配置 - 优先级策略
+ *
+ * 始终优先选择配置列表中的第一个健康实例,
+ * 首选实例不可用时按配置顺序从剩余健康实例中选取。
*
- * 替代默认的 RoundRobin 轮询策略,在存活实例间随机分配请求。
+ * 通过 {@link SimpleDiscoveryProperties} 读取原始配置顺序,
+ * 确保健康检查并发返回结果后仍能正确识别首选实例。
*
* @author zdxt
*/
@@ -20,13 +28,23 @@ import org.springframework.core.env.Environment;
public class LoadBalancerConfig {
@Bean
- public ReactorLoadBalancer randomLoadBalancer(
+ public ReactorLoadBalancer preferredFirstLoadBalancer(
Environment environment,
- LoadBalancerClientFactory loadBalancerClientFactory) {
+ LoadBalancerClientFactory loadBalancerClientFactory,
+ SimpleDiscoveryProperties discoveryProperties) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
- return new RandomLoadBalancer(
+
+ // 从配置中获取该服务的原始实例顺序(即优先级)
+ List preferredOrder = discoveryProperties.getInstances()
+ .getOrDefault(name, Collections.emptyList())
+ .stream()
+ .map(instance -> instance.getHost() + ":" + instance.getPort())
+ .collect(Collectors.toList());
+
+ return new PreferredFirstLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
- name
+ name,
+ preferredOrder
);
}
}
diff --git a/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/config/PreferredFirstLoadBalancer.java b/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/config/PreferredFirstLoadBalancer.java
new file mode 100644
index 00000000..8d534cc2
--- /dev/null
+++ b/zdxt-web-server/zdxt-gateway-web-server/src/main/java/com/zdxt/gateway/webserver/config/PreferredFirstLoadBalancer.java
@@ -0,0 +1,79 @@
+package com.zdxt.gateway.webserver.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.DefaultResponse;
+import org.springframework.cloud.client.loadbalancer.EmptyResponse;
+import org.springframework.cloud.client.loadbalancer.Request;
+import org.springframework.cloud.client.loadbalancer.Response;
+import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
+import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
+import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+/**
+ * 优先级负载均衡器 - 首选优先策略
+ *
+ * 根据配置文件中实例的声明顺序确定优先级,
+ * 始终选择优先级最高的健康实例。
+ *
+ * 健康检查并发执行后返回结果顺序不确定,
+ * 因此通过 preferredOrder 显式匹配配置中的优先级顺序。
+ *
+ * @author zdxt
+ */
+@Slf4j
+public class PreferredFirstLoadBalancer implements ReactorServiceInstanceLoadBalancer {
+
+ private final String serviceId;
+ private final ObjectProvider serviceInstanceListSupplierProvider;
+ /** 配置中声明的实例顺序(host:port),索引越小优先级越高 */
+ private final List preferredOrder;
+
+ public PreferredFirstLoadBalancer(
+ ObjectProvider serviceInstanceListSupplierProvider,
+ String serviceId,
+ List preferredOrder) {
+ this.serviceId = serviceId;
+ this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
+ this.preferredOrder = preferredOrder;
+ log.info("[{}] 优先级顺序: {}", serviceId, preferredOrder);
+ }
+
+ @Override
+ public Mono> choose(Request request) {
+ ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
+ .getIfAvailable(NoopServiceInstanceListSupplier::new);
+ return supplier.get(request)
+ .next()
+ .map(this::selectInstance);
+ }
+
+ private Response selectInstance(List instances) {
+ if (instances.isEmpty()) {
+ log.warn("[{}] 无可用服务实例", serviceId);
+ return new EmptyResponse();
+ }
+
+ // 按配置优先级顺序遍历,找到第一个在健康列表中的实例
+ for (String preferred : preferredOrder) {
+ for (ServiceInstance instance : instances) {
+ String key = instance.getHost() + ":" + instance.getPort();
+ if (preferred.equals(key)) {
+ log.debug("[{}] 选择优先实例: {}, 健康实例数: {}",
+ serviceId, key, instances.size());
+ return new DefaultResponse(instance);
+ }
+ }
+ }
+
+ // 如果配置顺序中的实例都不在健康列表中(不应发生),取健康列表第一个
+ ServiceInstance fallback = instances.get(0);
+ log.warn("[{}] 未匹配到配置优先级实例,回退使用: {}:{}",
+ serviceId, fallback.getHost(), fallback.getPort());
+ return new DefaultResponse(fallback);
+ }
+}
diff --git a/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application-dev.yml b/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application-dev.yml
index e680baf2..944ff93b 100644
--- a/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application-dev.yml
+++ b/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application-dev.yml
@@ -43,6 +43,13 @@ spring:
filters:
- StripPrefix=1
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
+ - id: job-service
+ uri: http://localhost:18003
+ predicates:
+ - Path=/job-ep/**
+ filters:
+ - StripPrefix=1
+ - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
# Actuator监控端点配置
management:
diff --git a/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application-prod.yml b/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application-prod.yml
index e6cb4d27..79cbbb4d 100644
--- a/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application-prod.yml
+++ b/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application-prod.yml
@@ -5,14 +5,22 @@ spring:
application:
name: zdxt-gateway
cloud:
- # 静态服务实例列表(无需注册中心)
+ # 静态服务实例列表(无需注册中心,配置顺序即优先级)
discovery:
client:
simple:
instances:
- backend-service:
+ ent-ep-service:
- uri: http://10.76.108.7:18000
+ - uri: http://10.76.108.8:18002
+ - uri: http://10.76.108.9:18001
+ enf-ep-service:
+ - uri: http://10.76.108.8:18002
+ - uri: http://10.76.108.7:18000
+ - uri: http://10.76.108.9:18001
+ sup-ep-service:
- uri: http://10.76.108.9:18001
+ - uri: http://10.76.108.7:18000
- uri: http://10.76.108.8:18002
# LoadBalancer 健康检查配置
loadbalancer:
@@ -37,29 +45,36 @@ spring:
allowedHeaders: "*"
allowCredentials: true
maxAge: 3600
- # 路由配置 - 使用 lb:// 协议启用负载均衡
+ # 路由配置 - 使用 lb:// 协议启用优先级负载均衡
routes:
- id: enterprise-service
- uri: lb://backend-service
+ uri: lb://ent-ep-service
predicates:
- Path=/ent-ep/**
filters:
- StripPrefix=1
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
- id: supervision-service
- uri: lb://backend-service
+ uri: lb://sup-ep-service
predicates:
- Path=/sup-ep/**
filters:
- StripPrefix=1
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
- id: enforcement-service
- uri: lb://backend-service
+ uri: lb://enf-ep-service
predicates:
- Path=/enf-ep/**
filters:
- StripPrefix=1
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
+ - id: job-service
+ uri: http://10.76.108.10:18003
+ predicates:
+ - Path=/job-ep/**
+ filters:
+ - StripPrefix=1
+ - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
# Actuator监控端点配置
management:
diff --git a/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application.yml b/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application.yml
index da7585f7..cf55ca89 100644
--- a/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application.yml
+++ b/zdxt-web-server/zdxt-gateway-web-server/src/main/resources/application.yml
@@ -5,14 +5,22 @@ spring:
application:
name: zdxt-gateway
cloud:
- # 静态服务实例列表(无需注册中心)
+ # 静态服务实例列表(无需注册中心,配置顺序即优先级)
discovery:
client:
simple:
instances:
- backend-service:
+ ent-ep-service:
- uri: http://localhost:18000
+ - uri: http://localhost:18002
+ - uri: http://localhost:18001
+ enf-ep-service:
+ - uri: http://localhost:18002
+ - uri: http://localhost:18000
+ - uri: http://localhost:18001
+ sup-ep-service:
- uri: http://localhost:18001
+ - uri: http://localhost:18000
- uri: http://localhost:18002
# LoadBalancer 健康检查配置
loadbalancer:
@@ -37,29 +45,36 @@ spring:
allowedHeaders: "*"
allowCredentials: true
maxAge: 3600
- # 路由配置 - 使用 lb:// 协议启用负载均衡
+ # 路由配置 - 使用 lb:// 协议启用优先级负载均衡
routes:
- id: enterprise-service
- uri: lb://backend-service
+ uri: lb://ent-ep-service
predicates:
- Path=/ent-ep/**
filters:
- StripPrefix=1
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
- id: supervision-service
- uri: lb://backend-service
+ uri: lb://sup-ep-service
predicates:
- Path=/sup-ep/**
filters:
- StripPrefix=1
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
- id: enforcement-service
- uri: lb://backend-service
+ uri: lb://enf-ep-service
predicates:
- Path=/enf-ep/**
filters:
- StripPrefix=1
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
+ - id: job-service
+ uri: http://localhost:18003
+ predicates:
+ - Path=/job-ep/**
+ filters:
+ - StripPrefix=1
+ - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
# Actuator监控端点配置
management: