mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-08 04:39:00 +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
|
||||
* @date 2020-02-08 认证授权中心
|
||||
*/
|
||||
@SpringCloudApplication
|
||||
@EnablePigxFeignClients
|
||||
@SpringCloudApplication
|
||||
public class PigxAuthApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
-1
@@ -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 {
|
||||
|
||||
+4
-12
@@ -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() {
|
||||
+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=\
|
||||
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
|
||||
@SpringCloudApplication
|
||||
@EnablePigxFeignClients
|
||||
@SpringCloudApplication
|
||||
@EnablePigxResourceServer
|
||||
public class PigxAdminApplication {
|
||||
|
||||
|
||||
+1
-1
@@ -30,8 +30,8 @@ import org.springframework.cloud.client.SpringCloudApplication;
|
||||
* 支付模块
|
||||
*/
|
||||
@EnablePigxSwagger2
|
||||
@SpringCloudApplication
|
||||
@EnablePigxFeignClients
|
||||
@SpringCloudApplication
|
||||
@EnablePigxResourceServer
|
||||
public class PigxPayPlatformApplication {
|
||||
|
||||
|
||||
Reference in new issue
Block a user