潘志宝
5 天以前 6d75723f3e3bd43895db2470bc5fabb2314dbe8b
提交 | 用户 | 时间
e7c126 1 package com.iailab.framework.env.core.fegin;
H 2
3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.StrUtil;
5 import com.iailab.framework.common.util.collection.CollectionUtils;
6 import com.iailab.framework.env.core.context.EnvContextHolder;
7 import com.iailab.framework.env.core.util.EnvUtils;
8 import com.alibaba.cloud.nacos.balancer.NacosBalancer;
9 import lombok.RequiredArgsConstructor;
10 import lombok.extern.slf4j.Slf4j;
11 import org.springframework.beans.factory.ObjectProvider;
12 import org.springframework.cloud.client.ServiceInstance;
13 import org.springframework.cloud.client.loadbalancer.DefaultResponse;
14 import org.springframework.cloud.client.loadbalancer.EmptyResponse;
15 import org.springframework.cloud.client.loadbalancer.Request;
16 import org.springframework.cloud.client.loadbalancer.Response;
17 import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
18 import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
19 import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
20 import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
21 import reactor.core.publisher.Mono;
22
23 import java.util.List;
24
25 /**
26  * 多环境的 {@link org.springframework.cloud.client.loadbalancer.LoadBalancerClient} 实现类
27  * 在从服务实例列表选择时,优先选择 tag 匹配的服务实例
28  *
29  * @author iailab
30  */
31 @RequiredArgsConstructor
32 @Slf4j
33 public class EnvLoadBalancerClient implements ReactorServiceInstanceLoadBalancer {
34
35     /**
36      * 用于获取 serviceId 对应的服务实例的列表
37      */
38     private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
39     /**
40      * 需要获取的服务实例名
41      *
42      * 暂时用于打印 logger 日志
43      */
44     private final String serviceId;
45     /**
46      * 被代理的 ReactiveLoadBalancer 对象
47      */
48     private final ReactiveLoadBalancer<ServiceInstance> reactiveLoadBalancer;
49
50     @Override
51     public Mono<Response<ServiceInstance>> choose(Request request) {
52         // 情况一,没有 tag 时,使用默认的 reactiveLoadBalancer 实现负载均衡
53         String tag = EnvContextHolder.getTag();
54         if (StrUtil.isEmpty(tag)) {
55             return Mono.from(reactiveLoadBalancer.choose(request));
56         }
57
58         // 情况二,有 tag 时,使用 tag 匹配服务实例
59         ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
60         return supplier.get(request).next().map(list -> getInstanceResponse(list, tag));
61     }
62
63     private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, String tag) {
64         // 如果服务实例为空,则直接返回
65         if (CollUtil.isEmpty(instances)) {
66             log.warn("[getInstanceResponse][serviceId({}) 服务实例列表为空]", serviceId);
67             return new EmptyResponse();
68         }
69
70         // 筛选满足条件的实例列表
71         List<ServiceInstance> chooseInstances = CollectionUtils.filterList(instances, instance -> tag.equals(EnvUtils.getTag(instance)));
72         if (CollUtil.isEmpty(chooseInstances)) {
73             log.warn("[getInstanceResponse][serviceId({}) 没有满足 tag({}) 的服务实例列表,直接使用所有服务实例列表]", serviceId, tag);
74             chooseInstances = instances;
75         }
76
77         // TODO iailab:https://juejin.cn/post/7056770721858469896 想通网段
78
79         // 随机 + 权重获取实例列表 TODO iailab:目前直接使用 Nacos 提供的方法,如果替换注册中心,需要重新失败该方法
80         return new DefaultResponse(NacosBalancer.getHostByRandomWeight3(chooseInstances));
81     }
82
83 }