mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-15 06:29:01 +08:00
✨ Introducing new features. #2207 适配兼容 Spring Cloud 2020 && Spring Boot 2.4
This commit is contained in:
1 parent
a25caeff01
commit
bf2ce5cffd
11 files changed
+162
-100
No files matched your search
@@ -27,8 +27,8 @@ import org.springframework.cloud.client.SpringCloudApplication;
|
|||||||
* @author lengleng
|
* @author lengleng
|
||||||
* @date 2020-02-08 认证授权中心
|
* @date 2020-02-08 认证授权中心
|
||||||
*/
|
*/
|
||||||
@SpringCloudApplication
|
|
||||||
@EnablePigxFeignClients
|
@EnablePigxFeignClients
|
||||||
|
@SpringCloudApplication
|
||||||
public class PigxAuthApplication {
|
public class PigxAuthApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
-1
@@ -33,7 +33,6 @@ import java.lang.annotation.*;
|
|||||||
@Documented
|
@Documented
|
||||||
@EnableFeignClients
|
@EnableFeignClients
|
||||||
@Import(PigxFeignClientsRegistrar.class)
|
@Import(PigxFeignClientsRegistrar.class)
|
||||||
// 排除 Ribbon (当然也可以排查 maven 依赖)
|
|
||||||
@EnableAutoConfiguration(excludeName =
|
@EnableAutoConfiguration(excludeName =
|
||||||
"org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration")
|
"org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration")
|
||||||
public @interface EnablePigxFeignClients {
|
public @interface EnablePigxFeignClients {
|
||||||
|
|||||||
+4
-12
@@ -18,14 +18,12 @@
|
|||||||
package com.pig4cloud.pigx.common.gray;
|
package com.pig4cloud.pigx.common.gray;
|
||||||
|
|
||||||
import com.pig4cloud.pigx.common.gray.feign.GrayFeignRequestInterceptor;
|
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 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.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author lengleng
|
* @author lengleng
|
||||||
@@ -33,14 +31,8 @@ import org.springframework.context.annotation.Scope;
|
|||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnProperty(value = "gray.rule.enabled", havingValue = "true")
|
@ConditionalOnProperty(value = "gray.rule.enabled", havingValue = "true")
|
||||||
public class GrayRibbonLoadBalancerConfiguration {
|
@Import(GrayLoadBalancerClientConfigurationRegistrar.class)
|
||||||
|
public class GrayLoadBalancerAutoConfiguration {
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
|
||||||
public GrayRibbonLoadBalancerRule ribbonLoadBalancerRule() {
|
|
||||||
return new GrayRibbonLoadBalancerRule();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RequestInterceptor grayFeignRequestInterceptor() {
|
public RequestInterceptor grayFeignRequestInterceptor() {
|
||||||
+26
@@ -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<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
|
||||||
|
LoadBalancerClientFactory loadBalancerClientFactory) {
|
||||||
|
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
|
||||||
|
return new GrayRoundRobinLoadBalancer(
|
||||||
|
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
-83
@@ -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<Server> 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<String, String> 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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+84
@@ -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<ServiceInstanceListSupplier> 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<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
|
||||||
|
super(serviceInstanceListSupplierProvider, serviceId);
|
||||||
|
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
|
||||||
|
this.serviceId = serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Response<ServiceInstance>> choose(Request request) {
|
||||||
|
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
|
||||||
|
.getIfAvailable(NoopServiceInstanceListSupplier::new);
|
||||||
|
return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, request));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> 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<String, String> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
com.pig4cloud.pigx.common.gray.GrayRibbonLoadBalancerConfiguration
|
com.pig4cloud.pigx.common.gray.GrayLoadBalancerAutoConfiguration
|
||||||
+1
-1
@@ -32,8 +32,8 @@ import org.springframework.cloud.client.SpringCloudApplication;
|
|||||||
* 用户统一管理系统
|
* 用户统一管理系统
|
||||||
*/
|
*/
|
||||||
@EnablePigxSwagger2
|
@EnablePigxSwagger2
|
||||||
@SpringCloudApplication
|
|
||||||
@EnablePigxFeignClients
|
@EnablePigxFeignClients
|
||||||
|
@SpringCloudApplication
|
||||||
@EnablePigxResourceServer
|
@EnablePigxResourceServer
|
||||||
public class PigxAdminApplication {
|
public class PigxAdminApplication {
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -30,8 +30,8 @@ import org.springframework.cloud.client.SpringCloudApplication;
|
|||||||
* 支付模块
|
* 支付模块
|
||||||
*/
|
*/
|
||||||
@EnablePigxSwagger2
|
@EnablePigxSwagger2
|
||||||
@SpringCloudApplication
|
|
||||||
@EnablePigxFeignClients
|
@EnablePigxFeignClients
|
||||||
|
@SpringCloudApplication
|
||||||
@EnablePigxResourceServer
|
@EnablePigxResourceServer
|
||||||
public class PigxPayPlatformApplication {
|
public class PigxPayPlatformApplication {
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,11 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!--bootstrap 启动器-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||||
|
</dependency>
|
||||||
<!--配置文件处理器-->
|
<!--配置文件处理器-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|||||||
Reference in new issue
Block a user