From 41d85abf23c123e948b1a585c413f5a0a29a504f Mon Sep 17 00:00:00 2001 From: bluejay <253316343@qq.com> Date: 星期二, 08 四月 2025 09:05:49 +0800 Subject: [PATCH] gateway 根据matedate转发到本地服务 --- aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayLoadBalancer.java | 10 +++ aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayReactiveLoadBalancerClientFilter.java | 99 +++++++++++++++++++++++++++++++++ aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/VersionGrayLoadBalancer.java | 60 ++++++++++++++++++++ aps-gateway/pom.xml | 11 +++ 4 files changed, 179 insertions(+), 1 deletions(-) diff --git a/aps-gateway/pom.xml b/aps-gateway/pom.xml index d5b6905..4e0cb1f 100644 --- a/aps-gateway/pom.xml +++ b/aps-gateway/pom.xml @@ -82,7 +82,16 @@ <artifactId>springdoc-openapi-starter-webflux-ui</artifactId> <version>${springdoc.version}</version> </dependency> - + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>cn.hutool</groupId> + <artifactId>hutool-all</artifactId> + <version>5.8.37</version> + </dependency> </dependencies> <build> diff --git a/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayLoadBalancer.java b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayLoadBalancer.java new file mode 100644 index 0000000..1bf7457 --- /dev/null +++ b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayLoadBalancer.java @@ -0,0 +1,10 @@ +package com.aps.gateway.config.loadBalancer; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.http.server.reactive.ServerHttpRequest; + + +public interface GrayLoadBalancer { + + ServiceInstance choose(String serviceId, ServerHttpRequest request); +} diff --git a/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayReactiveLoadBalancerClientFilter.java b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayReactiveLoadBalancerClientFilter.java new file mode 100644 index 0000000..fb73979 --- /dev/null +++ b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayReactiveLoadBalancerClientFilter.java @@ -0,0 +1,99 @@ +package com.aps.gateway.config.loadBalancer; + +import lombok.extern.slf4j.Slf4j; +import org.apache.http.util.Asserts; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.DefaultResponse; +import org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools; +import org.springframework.cloud.client.loadbalancer.Response; +import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter; +import org.springframework.cloud.gateway.support.DelegatingServiceInstance; +import org.springframework.cloud.gateway.support.NotFoundException; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.net.URI; + + +@Slf4j +@Component +public class GrayReactiveLoadBalancerClientFilter extends ReactiveLoadBalancerClientFilter { + + private final static String SCHEME = "lb"; + + private static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150; + private final GrayLoadBalancer grayLoadBalancer; + private final GatewayLoadBalancerProperties loadBalancerProperties; + + public GrayReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, GatewayLoadBalancerProperties loadBalancerProperties, GrayLoadBalancer grayLoadBalancer) { + super(clientFactory, loadBalancerProperties); + this.loadBalancerProperties = loadBalancerProperties; + this.grayLoadBalancer = grayLoadBalancer; + } + + @Override + public int getOrder() { + return LOAD_BALANCER_CLIENT_FILTER_ORDER; + } + + @Override + public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { + URI url = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); + String schemePrefix = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR); + + // 鐩存帴鏀捐 + if (url == null || (!SCHEME.equals(url.getScheme()) && !SCHEME.equals(schemePrefix))) { + return chain.filter(exchange); + } + // 淇濈暀鍘熷url + ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url); + + if (log.isTraceEnabled()) { + log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url); + } + + return choose(exchange).doOnNext(response -> { + + if (!response.hasServer()) { + throw NotFoundException.create(loadBalancerProperties.isUse404(), + "Unable to find instance for " + url.getHost()); + } + + URI uri = exchange.getRequest().getURI(); + + // if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default, + // if the loadbalancer doesn't provide one. + String overrideScheme = null; + if (schemePrefix != null) { + overrideScheme = url.getScheme(); + } + + DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(response.getServer(), + overrideScheme); + + URI requestUrl = LoadBalancerUriTools.reconstructURI(serviceInstance, uri); + + if (log.isTraceEnabled()) { + log.trace("LoadBalancerClientFilter url chosen: " + requestUrl); + } + exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl); + }).then(chain.filter(exchange)); + } + + /** + * 鑾峰彇瀹炰緥 + * @param exchange ServerWebExchange + * @return ServiceInstance + */ + private Mono<Response<ServiceInstance>> choose(ServerWebExchange exchange) { + URI uri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); + Asserts.notNull(uri, "uri"); + ServiceInstance serviceInstance = grayLoadBalancer.choose(uri.getHost(), exchange.getRequest()); + return Mono.just(new DefaultResponse(serviceInstance)); + } +} \ No newline at end of file diff --git a/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/VersionGrayLoadBalancer.java b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/VersionGrayLoadBalancer.java new file mode 100644 index 0000000..8946d45 --- /dev/null +++ b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/VersionGrayLoadBalancer.java @@ -0,0 +1,60 @@ +package com.aps.gateway.config.loadBalancer; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.gateway.support.NotFoundException; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@RequiredArgsConstructor +@Component +public class VersionGrayLoadBalancer implements GrayLoadBalancer { + + private final DiscoveryClient discoveryClient; + private final static String VERSION = "version"; + /** + * 鏍规嵁serviceId 绛涢�夊彲鐢ㄦ湇鍔� + * @param serviceId 鏈嶅姟ID + * @param request 褰撳墠璇锋眰 + * @return ServiceInstance + */ + @Override + public ServiceInstance choose(String serviceId, ServerHttpRequest request) { + List<ServiceInstance> instances = discoveryClient.getInstances(serviceId); + + // 娉ㄥ唽涓績鏃犲疄渚� 鎶涘嚭寮傚父 + if (instances.isEmpty()) { + log.warn("No instance available for {}", serviceId); + throw new NotFoundException("No instance available for " + serviceId); + } + + // 鑾峰彇璇锋眰version锛屾棤鍒欓殢鏈鸿繑鍥炲彲鐢ㄥ疄渚� + String reqVersion = request.getHeaders().getFirst(VERSION); + if (Strings.isBlank(reqVersion)) { + return instances.get(RandomUtil.randomInt(instances.size())); + } + + // 閬嶅巻鍙互瀹炰緥鍏冩暟鎹紝鑻ュ尮閰嶅垯杩斿洖姝ゅ疄渚� + List<ServiceInstance> availableList = instances.stream() + .filter(instance -> reqVersion + .equalsIgnoreCase(MapUtil.getStr(instance.getMetadata(), VERSION))) + .collect(Collectors.toList()); + + if (CollUtil.isEmpty(availableList)) { + return instances.get(RandomUtil.randomInt(instances.size())); + } + return availableList.get(RandomUtil.randomInt(availableList.size())); + + } +} + -- Gitblit v1.9.3