package org.dromara.common.loadbalance.core;
|
|
import cn.hutool.core.net.NetUtil;
|
import lombok.AllArgsConstructor;
|
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.SelectedInstanceCallback;
|
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
|
import reactor.core.publisher.Mono;
|
|
import java.util.List;
|
import java.util.concurrent.ThreadLocalRandom;
|
|
/**
|
* 自定义 SpringCloud 负载均衡算法
|
*
|
* @author Lion Li
|
*/
|
@Slf4j
|
@AllArgsConstructor
|
public class CustomSpringCloudLoadBalancer implements ReactorServiceInstanceLoadBalancer {
|
|
private final String serviceId;
|
|
private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
|
|
@Override
|
public Mono<Response<ServiceInstance>> choose(Request request) {
|
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
|
return supplier.get(request).next().map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
|
}
|
|
private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,
|
List<ServiceInstance> serviceInstances) {
|
Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances);
|
if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
|
((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
|
}
|
return serviceInstanceResponse;
|
}
|
|
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
|
if (instances.isEmpty()) {
|
if (log.isWarnEnabled()) {
|
log.warn("No servers available for service: " + serviceId);
|
}
|
return new EmptyResponse();
|
}
|
for (ServiceInstance instance : instances) {
|
if (NetUtil.localIpv4s().contains(instance.getHost())) {
|
return new DefaultResponse(instance);
|
}
|
}
|
return new DefaultResponse(instances.get(ThreadLocalRandom.current().nextInt(instances.size())));
|
}
|
|
}
|