From bf2ce5cffd9d21d720c4eaeee7237d71b30cd521 Mon Sep 17 00:00:00 2001 From: lengleng Date: Wed, 30 Dec 2020 11:31:51 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20Introducing=20new=20features.=20#2?= =?UTF-8?q?207=20=E9=80=82=E9=85=8D=E5=85=BC=E5=AE=B9=20Spring=20Cloud=202?= =?UTF-8?q?020=20&&=20Spring=20Boot=202.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pigx/auth/PigxAuthApplication.java | 2 +- .../annotation/EnablePigxFeignClients.java | 1 - ...=> GrayLoadBalancerAutoConfiguration.java} | 16 +--- .../GrayLoadBalancerClientConfiguration.java | 26 ++++++ ...dBalancerClientConfigurationRegistrar.java | 39 +++++++++ .../gray/rule/GrayRibbonLoadBalancerRule.java | 83 ------------------ .../gray/rule/GrayRoundRobinLoadBalancer.java | 84 +++++++++++++++++++ .../main/resources/META-INF/spring.factories | 2 +- .../pigx/admin/PigxAdminApplication.java | 2 +- .../pigx/pay/PigxPayPlatformApplication.java | 2 +- pom.xml | 5 ++ 11 files changed, 162 insertions(+), 100 deletions(-) rename pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/{GrayRibbonLoadBalancerConfiguration.java => GrayLoadBalancerAutoConfiguration.java} (72%) create mode 100644 pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayLoadBalancerClientConfiguration.java create mode 100755 pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayLoadBalancerClientConfigurationRegistrar.java delete mode 100644 pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRibbonLoadBalancerRule.java create mode 100755 pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRoundRobinLoadBalancer.java diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java index 7cb973006..a381ea61e 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java @@ -27,8 +27,8 @@ import org.springframework.cloud.client.SpringCloudApplication; * @author lengleng * @date 2020-02-08 认证授权中心 */ -@SpringCloudApplication @EnablePigxFeignClients +@SpringCloudApplication public class PigxAuthApplication { public static void main(String[] args) { diff --git a/pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/annotation/EnablePigxFeignClients.java b/pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/annotation/EnablePigxFeignClients.java index c153fc3a8..c7f0e9418 100644 --- a/pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/annotation/EnablePigxFeignClients.java +++ b/pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/annotation/EnablePigxFeignClients.java @@ -33,7 +33,6 @@ import java.lang.annotation.*; @Documented @EnableFeignClients @Import(PigxFeignClientsRegistrar.class) -// 排除 Ribbon (当然也可以排查 maven 依赖) @EnableAutoConfiguration(excludeName = "org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration") public @interface EnablePigxFeignClients { diff --git a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/GrayRibbonLoadBalancerConfiguration.java b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/GrayLoadBalancerAutoConfiguration.java similarity index 72% rename from pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/GrayRibbonLoadBalancerConfiguration.java rename to pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/GrayLoadBalancerAutoConfiguration.java index 5c004b24b..6a9b9969b 100644 --- a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/GrayRibbonLoadBalancerConfiguration.java +++ b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/GrayLoadBalancerAutoConfiguration.java @@ -18,14 +18,12 @@ package com.pig4cloud.pigx.common.gray; import com.pig4cloud.pigx.common.gray.feign.GrayFeignRequestInterceptor; -import com.pig4cloud.pigx.common.gray.rule.GrayRibbonLoadBalancerRule; +import com.pig4cloud.pigx.common.gray.rule.GrayLoadBalancerClientConfigurationRegistrar; import feign.RequestInterceptor; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.Import; /** * @author lengleng @@ -33,14 +31,8 @@ import org.springframework.context.annotation.Scope; */ @Configuration @ConditionalOnProperty(value = "gray.rule.enabled", havingValue = "true") -public class GrayRibbonLoadBalancerConfiguration { - - @Bean - @ConditionalOnMissingBean - @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public GrayRibbonLoadBalancerRule ribbonLoadBalancerRule() { - return new GrayRibbonLoadBalancerRule(); - } +@Import(GrayLoadBalancerClientConfigurationRegistrar.class) +public class GrayLoadBalancerAutoConfiguration { @Bean public RequestInterceptor grayFeignRequestInterceptor() { diff --git a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayLoadBalancerClientConfiguration.java b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayLoadBalancerClientConfiguration.java new file mode 100644 index 000000000..3b82cd1d7 --- /dev/null +++ b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayLoadBalancerClientConfiguration.java @@ -0,0 +1,26 @@ +package com.pig4cloud.pigx.common.gray.rule; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration; +import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; + +/** + * @author lengleng + * @date 2020/12/29 + */ +public class GrayLoadBalancerClientConfiguration extends LoadBalancerClientConfiguration { + + @Bean + @ConditionalOnMissingBean + public ReactorLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment, + LoadBalancerClientFactory loadBalancerClientFactory) { + String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); + return new GrayRoundRobinLoadBalancer( + loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); + } +} diff --git a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayLoadBalancerClientConfigurationRegistrar.java b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayLoadBalancerClientConfigurationRegistrar.java new file mode 100755 index 000000000..84f32ef7c --- /dev/null +++ b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayLoadBalancerClientConfigurationRegistrar.java @@ -0,0 +1,39 @@ +package com.pig4cloud.pigx.common.gray.rule; + +import cn.hutool.core.util.ReflectUtil; +import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientSpecification; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.type.AnnotationMetadata; + +import java.lang.reflect.Field; + +/** + * @author lengleng + * @date 2020/11/20 + */ +public class GrayLoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar { + + + private static void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, + Object configuration) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder + .genericBeanDefinition(LoadBalancerClientSpecification.class); + builder.addConstructorArgValue(name); + builder.addConstructorArgValue(configuration); + registry.registerBeanDefinition(name + ".LoadBalancerClientSpecification", builder.getBeanDefinition()); + } + + @Override + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { + Field[] fields = ReflectUtil.getFields(ServiceNameConstants.class); + + // 遍历服务名称,注入支持灰度策略的负载均衡器 + for (Field field : fields) { + Object fieldValue = ReflectUtil.getFieldValue(ServiceNameConstants.class, field); + registerClientConfiguration(registry, fieldValue, GrayLoadBalancerClientConfiguration.class); + } + } +} diff --git a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRibbonLoadBalancerRule.java b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRibbonLoadBalancerRule.java deleted file mode 100644 index 49d6f492d..000000000 --- a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRibbonLoadBalancerRule.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - */ - -package com.pig4cloud.pigx.common.gray.rule; - -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 com.alibaba.cloud.nacos.ribbon.NacosServer; -import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.AbstractLoadBalancerRule; -import com.netflix.loadbalancer.ILoadBalancer; -import com.netflix.loadbalancer.Server; -import com.pig4cloud.pigx.common.core.constant.CommonConstants; -import com.pig4cloud.pigx.common.core.util.WebUtils; -import com.pig4cloud.pigx.common.gray.support.NonWebVersionContextHolder; -import lombok.extern.slf4j.Slf4j; - -import java.util.List; -import java.util.Map; - -/** - * @author lengleng - * @date 2020/1/12 - */ -@Slf4j -public class GrayRibbonLoadBalancerRule extends AbstractLoadBalancerRule { - - @Override - public void initWithNiwsConfig(IClientConfig iClientConfig) { - } - - @Override - public Server choose(Object key) { - return choose(getLoadBalancer(), key); - } - - public Server choose(ILoadBalancer lb, Object key) { - List reachableServers = lb.getReachableServers(); - - // 注册中心无可用实例 抛出异常 - if (CollUtil.isEmpty(reachableServers)) { - log.warn("No instance available for {}", key); - return null; - } - - // 获取请求version,无则随机返回可用实例 - String reqVersion = WebUtils.getRequest() != null ? WebUtils.getRequest().getHeader(CommonConstants.VERSION) - : NonWebVersionContextHolder.getVersion(); - - if (StrUtil.isBlank(reqVersion)) { - return reachableServers.get(RandomUtil.randomInt(reachableServers.size())); - } - - // 遍历可以实例元数据,若匹配则返回此实例 - for (Server server : reachableServers) { - NacosServer nacosServer = (NacosServer) server; - Map metadata = nacosServer.getMetadata(); - String targetVersion = MapUtil.getStr(metadata, CommonConstants.VERSION); - if (reqVersion.equalsIgnoreCase(targetVersion)) { - log.debug("gray requst match success :{} {}", reqVersion, nacosServer); - return nacosServer; - } - } - return reachableServers.get(RandomUtil.randomInt(reachableServers.size())); - } - -} diff --git a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRoundRobinLoadBalancer.java b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRoundRobinLoadBalancer.java new file mode 100755 index 000000000..bca85b256 --- /dev/null +++ b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRoundRobinLoadBalancer.java @@ -0,0 +1,84 @@ +package com.pig4cloud.pigx.common.gray.rule; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.cloud.nacos.NacosServiceInstance; +import com.pig4cloud.pigx.common.core.constant.CommonConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.*; +import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.http.HttpHeaders; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +/** + * @author lengleng + * @date 2020/11/20 + */ +@Slf4j +public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer { + + private ObjectProvider serviceInstanceListSupplierProvider; + + private String serviceId; + + /** + * @param serviceInstanceListSupplierProvider a provider of + * {@link ServiceInstanceListSupplier} that will be used to get available instances + * @param serviceId id of the service for which to choose an instance + */ + public GrayRoundRobinLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider, String serviceId) { + super(serviceInstanceListSupplierProvider, serviceId); + this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider; + this.serviceId = serviceId; + } + + + @Override + public Mono> choose(Request request) { + ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider + .getIfAvailable(NoopServiceInstanceListSupplier::new); + return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, request)); + + } + + Response getInstanceResponse(List instances, Request request) { + + // 注册中心无可用实例 抛出异常 + if (CollUtil.isEmpty(instances)) { + log.warn("No instance available "); + return new EmptyResponse(); + } + + DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext(); + RequestData clientRequest = (RequestData) requestContext.getClientRequest(); + HttpHeaders headers = clientRequest.getHeaders(); + + String reqVersion = headers.getFirst(CommonConstants.VERSION); + if (StrUtil.isBlank(reqVersion)) { + return super.choose(request).block(); + } + + // 遍历可以实例元数据,若匹配则返回此实例 + for (ServiceInstance instance : instances) { + NacosServiceInstance nacosInstance = (NacosServiceInstance) instance; + Map metadata = nacosInstance.getMetadata(); + String targetVersion = MapUtil.getStr(metadata, CommonConstants.VERSION); + if (reqVersion.equalsIgnoreCase(targetVersion)) { + log.debug("gray requst match success :{} {}", reqVersion, nacosInstance); + return new DefaultResponse(nacosInstance); + } + } + + // 降级策略,使用轮询策略 + return super.choose(request).block(); + } + +} diff --git a/pigx-common/pigx-common-gray/src/main/resources/META-INF/spring.factories b/pigx-common/pigx-common-gray/src/main/resources/META-INF/spring.factories index 0dc0c1d27..29191e2e1 100644 --- a/pigx-common/pigx-common-gray/src/main/resources/META-INF/spring.factories +++ b/pigx-common/pigx-common-gray/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - com.pig4cloud.pigx.common.gray.GrayRibbonLoadBalancerConfiguration \ No newline at end of file + com.pig4cloud.pigx.common.gray.GrayLoadBalancerAutoConfiguration \ No newline at end of file diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/PigxAdminApplication.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/PigxAdminApplication.java index dd11172f8..325dc01c4 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/PigxAdminApplication.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/PigxAdminApplication.java @@ -32,8 +32,8 @@ import org.springframework.cloud.client.SpringCloudApplication; * 用户统一管理系统 */ @EnablePigxSwagger2 -@SpringCloudApplication @EnablePigxFeignClients +@SpringCloudApplication @EnablePigxResourceServer public class PigxAdminApplication { diff --git a/pigx-visual/pigx-pay-platform/src/main/java/com/pig4cloud/pigx/pay/PigxPayPlatformApplication.java b/pigx-visual/pigx-pay-platform/src/main/java/com/pig4cloud/pigx/pay/PigxPayPlatformApplication.java index e689dcfd2..d3dbf065e 100755 --- a/pigx-visual/pigx-pay-platform/src/main/java/com/pig4cloud/pigx/pay/PigxPayPlatformApplication.java +++ b/pigx-visual/pigx-pay-platform/src/main/java/com/pig4cloud/pigx/pay/PigxPayPlatformApplication.java @@ -30,8 +30,8 @@ import org.springframework.cloud.client.SpringCloudApplication; * 支付模块 */ @EnablePigxSwagger2 -@SpringCloudApplication @EnablePigxFeignClients +@SpringCloudApplication @EnablePigxResourceServer public class PigxPayPlatformApplication { diff --git a/pom.xml b/pom.xml index b18f0c081..124aad15e 100644 --- a/pom.xml +++ b/pom.xml @@ -66,6 +66,11 @@ + + + org.springframework.cloud + spring-cloud-starter-bootstrap + org.springframework.boot