IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> feign自定义负载到指定ip -> 正文阅读

[网络协议]feign自定义负载到指定ip

项目背景:目前使用的springcloud微服务架构,开发人员本地联调过程中,会用到许多并非自己开发的微服务支持。但是这样就需要启动多个应用,严重影响开发效率。现在架构组讨论写一个feign重负载,可以指定一次请求负载到具体ip。

大致想法:重写feign的负载均衡客户端LoadBalancerFeignClient,每次请求会执行excute方法,在excute方法中获取指定ip,替换feign已经负载好的ip。

遇到问题:配置类没加getset方法,导致无法读取配置文件;DiscoveryClient获取服务列表用getApplication方法,之前用的getInstance获取不到;版本问题,10.7.4feign-core版本拿到的url是ip,需要将ip替换为applicationname,否则调用多个feignclient会报错,具体原因还没扒出来。

上代码:

?重写的负载客户端:

@Slf4j
public class FeignReBalancer extends LoadBalancerFeignClient {

    private Client delegate;
    private CachingSpringLoadBalancerFactory lbClientFactory;
    private SpringClientFactory clientFactory;
    private ReBalancerProperties reBalancerProperties;

    public FeignReBalancer(Client delegate,
                           CachingSpringLoadBalancerFactory lbClientFactory,
                           SpringClientFactory clientFactory, ReBalancerProperties reBalancerProperties, DiscoveryClient discoveryClient){
        super(delegate, lbClientFactory, clientFactory);
        this.delegate = delegate;
        this.lbClientFactory = lbClientFactory;
        this.clientFactory = clientFactory;
        this.reBalancerProperties = reBalancerProperties;
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        log.info("feign开始负载均衡...");
        //重新负载后的url
        String balanceUrl = null;
        //原始url
        String url = request.url();
        //应用名
        String applicationName = request.requestTemplate().feignTarget().name();
        balanceUrl = newURL(url,applicationName);
        URI uri = URI.create(url);
        //应用ip
        String clientName = uri.getHost();
        int port = uri.getPort();
        //发起请求客户端的IP
        String requestIp = PubFun.threadLocal.get()==null?null:PubFun.threadLocal.get().getClientIp();
        //获取注册中心的所有服务ip
        DiscoveryClient discoveryClient = SpringContextUtils.getBeanByClass(DiscoveryClient.class);
        Application application = discoveryClient.getApplication(applicationName.toUpperCase());
        List<InstanceInfo> instances = application.getInstances();
        //如果ip没有注册,则走默认
        if(!instances.stream().anyMatch(instance -> instance.getHostName().equals(requestIp))){
            if(reBalancerProperties.servers != null &&
                    reBalancerProperties.servers.keySet().stream().anyMatch(key -> key.equals(applicationName))){
                clientName = reBalancerProperties.servers.get(applicationName);
            }else{
            }
        }else{
            //ip在注册中心,则替换为传入的ip
            clientName = requestIp;
        }
        //设置负载服务
        List<Server> allServers = this.clientFactory.getLoadBalancer(clientName).getAllServers();
        String finalHost = clientName;
        //如果不存在ip的负载服务,则设置,存在不需要设置
        if(!allServers.stream().anyMatch(server -> finalHost.equals(server.getHost()))){
            this.clientFactory.getLoadBalancer(clientName).addServers(Arrays.asList(new Server(clientName, port),new Server(applicationName)));
        }
        Response response = this.getResponse(request, options, balanceUrl);
        log.info("feign自定义负载至:"+clientName+":"+port+"完毕!");
        return response;
    }



    private Response getResponse(Request request, Request.Options options, String newUrl) throws IOException {
        //重新构建 request 对象
        Request newRequest = Request.create(request.method(),
                newUrl, request.headers(), request.body(),
                request.charset());

        return super.execute(newRequest, options);
    }

    /**
     * 将ip替换
     * @param url
     * @param ipAddress
     * @return
     */
    private String newURL(String url,String ipAddress){
        String[] split = url.split("/");
        split[2] = ipAddress;
        return Arrays.stream(split).reduce((s1, s2) -> s1+"/"+s2).get();
    }

}

注入上面的负载客户端

@ConditionalOnProperty(prefix = ReBalancerProperties.prefix,name = "enable",havingValue = "true")
@Configuration
@EnableConfigurationProperties(value = {ReBalancerProperties.class})
public class ReBalancerConfiguration {

    @Bean
    public Client feignReBalancer(CachingSpringLoadBalancerFactory cachingFactory,
                                  SpringClientFactory clientFactory, @Autowired(required = false) DiscoveryClient discoveryClient, ReBalancerProperties reBalancerProperties) {

        return new FeignReBalancer(new Client.Default(null, null),
                cachingFactory, clientFactory, reBalancerProperties, discoveryClient);
    }
}

配置类:

@ConfigurationProperties(prefix = ReBalancerProperties.prefix)
@Data
public class ReBalancerProperties {
    static final String prefix = "rebalancer";

    public Map<String,String> servers;

    public String test;
}

补充:自己的负载client是在TraceFeignAspect切面类加载的

@Aspect
class TraceFeignAspect {
    private static final Log log = LogFactory.getLog(TraceFeignAspect.class);
    private final BeanFactory beanFactory;

    TraceFeignAspect(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Around("execution (* feign.Client.*(..)) && !within(is(FinalType))")
    public Object feignClientWasCalled(final ProceedingJoinPoint pjp) throws Throwable {
        Object bean = pjp.getTarget();
        Object wrappedBean = (new TraceFeignObjectWrapper(this.beanFactory)).wrap(bean);
        if (log.isDebugEnabled()) {
            log.debug("Executing feign client via TraceFeignAspect");
        }

        return bean != wrappedBean ? this.executeTraceFeignClient(bean, pjp) : pjp.proceed();
    }

    Object executeTraceFeignClient(Object bean, ProceedingJoinPoint pjp) throws IOException {
        Object[] args = pjp.getArgs();
        Request request = (Request)args[0];
        Request.Options options = (Request.Options)args[1];
        return ((Client)bean).execute(request, options);
    }
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:20:34  更:2022-09-15 02:21:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 9:09:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码