聊聊不同集群的微服务如何通过feign调用

news2024/11/26 20:42:39

前言

之前业务部门的某项目微服务调用关系如下图


后因业务改造需要,该项目需要将服务A部署到另外一个集群,但服务A仍然需要能调用到服务B,调用关系如下图

之前调用方式是负责服务B的开发团队提供相应的feign客户端包给到服务A开发团队,服务A开发团队直接将客户端包引入到项目,在通过@EnableFeignClients来激活feign调用,现在跨了不同集群,而且2个集群间的注册中心也不一样,之前的调用方式就不大适用了。

业务部门的技术负责人就找到我们部门,看我们有没有什么方案。当时我们提供的方案,一种是服务A团队自己开发客户端接口去调用服务B,但这个方案工作量比较大。另外一种方案,就是通过改造openfeign。在业内一直很流行一句话,没有什么是加一层解决不了的

破局

后面我们提供的方案如下图


本质上就是原来服务A直接调用服务B,现在是服务A先通过和服务B同集群的网关,间接调用服务B。思路已经有了,但是我们需要实现业务能够少改代码,就能实现该需求

实现思路

通过feign的url + gateway开启基于服务注册中心自动服务路由功能

改造步骤

1、自定义注解EnableLybGeekFeignClients

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(LybGeekFeignClientsRegistrar.class)
public @interface EnableLybGeekFeignClients {

    /**
     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
     * declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
     * {@code @ComponentScan(basePackages="org.my.pkg")}.
     * @return the array of 'basePackages'.
     */
    String[] value() default {};

    /**
     * Base packages to scan for annotated components.
     * <p>
     * {@link #value()} is an alias for (and mutually exclusive with) this attribute.
     * <p>
     * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
     * package names.
     * @return the array of 'basePackages'.
     */
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages()} for specifying the packages to
     * scan for annotated components. The package of each class specified will be scanned.
     * <p>
     * Consider creating a special no-op marker class or interface in each package that
     * serves no purpose other than being referenced by this attribute.
     * @return the array of 'basePackageClasses'.
     */
    Class<?>[] basePackageClasses() default {};

    /**
     * A custom <code>@Configuration</code> for all feign clients. Can contain override
     * <code>@Bean</code> definition for the pieces that make up the client, for instance
     * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
     *
     * @return list of default configurations
     */
    Class<?>[] defaultConfiguration() default {};

    /**
     * List of classes annotated with @FeignClient. If not empty, disables classpath
     * scanning.
     * @return list of FeignClient classes
     */
    Class<?>[] clients() default {};
}

其实是照搬EnableFeignClients,差别只是import的bean不一样

2、扩展原生的FeignClientsRegistrar

扩展的核心内容如下

 @SneakyThrows
    private void registerFeignClient(BeanDefinitionRegistry registry,
                                     AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
        String className = annotationMetadata.getClassName();
        Class feignClientFactoryBeanClz = ClassUtils.forName("org.springframework.cloud.openfeign.FeignClientFactoryBean",Thread.currentThread().getContextClassLoader());
        String name = getName(attributes);
        String customUrl = getCustomUrl(getUrl(attributes),name);
        。。。省略其他代码
      
    }

    private String getCustomUrl(String url,String serviceName){
        if(StringUtils.hasText(url)){
            return url;
        }
        String gateWay = environment.getProperty("lybgeek.gateWayUrl");
        if(StringUtils.isEmpty(gateWay)){
            return url;
        }

        if(serviceName.startsWith("http://")){
            serviceName = StrUtil.trim(serviceName.replace("http://",""));
        }

        String customUrl = URLUtil.normalize(gateWay + "/" + serviceName);

        log.info("feign customed with new url:【{}】",customUrl);

        return customUrl;

    }

3、gateway开启基于服务注册中心自动服务路由功能

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true

测试

测试提供一个消费者、服务提供者、网关、注册中心

在消费者的启动类去掉原生的EnableFeignClients注解,采用我们自定义注解EnableLybGeekFeignClients

@SpringBootApplication
@EnableLybGeekFeignClients(basePackages = "com.github.lybgeek")
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class);
    }

}

消费者application.yml开启feign调用日志

logging:
  level:
    # feign调用所在的包
    com.github.lybgeek.api.feign: debug


feign:
  client:
    config:
      default:
        # 开启feign记录请求和响应的标题、正文和元数据
        loggerLevel: FULL

通过消费端调用服务提供者

可以正常访问,我们观察消费者控制台输出的信息


我们可以发现,此次调用,是服务与服务之间的调用,说明我们扩展的feign保留了原本feign的能力

我们对消费者的application.yml,新增如下内容

lybgeek:
  gateWayUrl: localhost:8000

再通过消费端调用服务提供者


可以正常访问,我们观察消费者控制台输出的信息

同时观察网关控制台输出的信息

我们可以发现,此次调用,是通过网关路由到服务再产生调用,说明我们扩展的feign已经具备通过网关请求服务的能力

总结

可能有朋友会说,何必这么麻烦扩展,直接通过

@FeignClient(name = "${feign.instance.svc:provider}",url="${lybgeek.gateWayUrl: }/${feign.instance.svc:provider}",path = InstanceServiceFeign.PATH,contextId = "instance")

不也可以实现。其实如果带入当时的业务场景考虑,就会发现这种方式,需要改的地方比直接扩展feign多得多,而且一旦出问题,不好集中回滚。有时候脱离业务场景,去谈论技术实现,会容易走偏

demo链接

https://github.com/lyb-geek/springboot-cloud-metadata-ext

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/718461.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三种Linux内核代码在线阅读工具

记录一下 1 . 可在线阅读uboot&#xff0c;kernel&#xff0c;busybox(rootfs)&#xff0c;可搜索字符串&#xff0c;函数跳 https://lxr.missinglinkelectronics.com/ 界面如下&#xff1a; 2. 显示界面跟代码编辑器很像&#xff0c;同样可以函数跳转 https://elixir.boot…

如何让罗技29方向盘像视频中的那样转动起来?

​​​​​​​[vlog]Autoware Carla G29 自动驾驶仿真_哔哩哔哩_bilibili 话接上文&#xff0c;在我之前一篇博客中已经讲解了如何给罗技29方向盘装上力反馈&#xff0c;也就是在拨动方向盘的时候感觉有一个力组织你过度的拨动方向盘&#xff0c;其实它真正的用处是用于实现对…

【Web3】认识区块链

目录 区块链特征 区块链类型 区块链的概念 区块链特征 去中心化&#xff1a;区块链是由一个分布在多个参与者之间的网络组成&#xff0c;没有中央机构或中介控制整个系统。所有参与者共同维护和验证账本的完整性&#xff0c;减少了单点故障和集中式控制的风险。共识机制&…

【HTTPS】采用的加密策略, 什么是中间人攻击? 什么是证书?

文章目录 前言一、认识 HTTPS 协议1, 对称加密2, 非对称加密 二、HTTPS 加密策略1, 只采用对称加密 : 不安全2, 引入非对称加密3, 中间人攻击之偷梁换柱4, 引入证书4.1 什么是证书4.2, 证书如何能解决"中间人攻击" 总结 前言 各位读者好, 我是小陈, 这是我的个人主页…

日历与时钟

目录 公历 黑色星期五 生物韵律 公历 在公历中&#xff0c;当年份为4的整数倍&#xff0c;但不是100的整数倍时&#xff0c;会出现闰年的现象。 y40 mod(y,4) 0 && mod(y,100)||mod(y,400)0 输出当时的年、月、日、时、分、秒 f%6d %6d %6d %6d %6d %9.3f\n cclock …

MySQL学习基础篇(八)---聚合函数

MySQL学习基础篇(八)—聚合函数 聚合&#xff08;或聚集、分组&#xff09;函数&#xff0c;它是对一组数据进行汇总的函数&#xff0c;输入的是一组数据的集合&#xff0c;输出的是单个值。 1. 聚合函数介绍 什么是聚合函数&#xff1a;聚合函数作用于一组数据&#xff0c;…

前端实战——尚品汇(网页开发)

/* 基础设置 */ .container {width: 1190px;margin: 0 auto; } /* #region顶部导航条start */ .topbar {height: 30px;background-color: #ececec; } .welcome {height: 30px;line-height: 30px;font-size: 0;color: #666; } .welcome span,.welcome a {font-size: 12px; } .we…

AIGC - Stable Diffusion WebUI 图像生成工具的环境配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131528224 Stable Diffusion WebUI 是一款基于深度学习的图像生成工具&#xff0c;根据用户的输入文本或图像&#xff0c;生成高质量的新图像&…

关于VMware虚拟空间的创建、Linux系统的安装

文章目录 前言一、Windows用户安装VMware软件1.1 下载VMware1.2 正常安装VMware后&#xff0c;该软件是要收费的&#xff0c;但是下面的链接可以让你使用很久 二、Mac用户安装VMware软件2.1 下载macOS版本&#xff1a;VMware Fusion2.2 正常安装VMware后&#xff0c;该软件是要…

「2024」预备研究生mem-形式逻辑强化:推矛盾

一、推矛盾 易错题&#xff1a;重点 重点&#xff1a; 二、课后题 三、每日一练

新版本vscode使用配置文件功能,解决不同项目使用不同的插件

如果你同时有vue2,vue3的项目。一定会遇到插件的问题。因为vue2项目插件是使用vetur的&#xff0c;vue3是使用volar的。 以前vscode为了在不同项目中能使用不同的配置文件&#xff0c;是使用工作区的概念去解决的&#xff0c;但是比较复杂而且不好用。 现在新版本的vscode&…

【温故而知新】Android架构模式

Android项目工程中常用的架构模式有MVC, MVP, MVVM以及现在新出的MVI。 下面一起温故而知新。 MVC MVC&#xff08;Model-View-Controller&#xff09;是一种在Android应用程序中使用的架构模式&#xff0c;用于实现松耦合、可测试和可维护的应用程序。 MVC架构模式包括三个…

高级篇十六、多版本并发控制(重要)

目录 1、什么是MVCC2、快照读与当前读2.1 快照读2.2 当前读 3、复习3.1 隔离级别3.2 隐藏字段、Undo Log版本链 4、MVCC实现原理之ReadView4.1 什么是ReadView&#xff1f; 1、什么是MVCC MVCC &#xff08;Multiversion Concurrency Control&#xff09;&#xff0c;多版本并…

Django之ORM的锁,开启事务,Ajax

一、行锁 select_for_update(nowaitFalse, skip_lockedFalse) 注意必须用在事务里面&#xff0c;至于如何开启事务&#xff0c;我们看下面的事务一节 Book.objects.select_for_update().filter(nid3) # 锁住nid3的行select_for_update中的两个参数了解即可&#xff0c;因为在…

机器学习入门

AI人工智能 ANI 弱人工智能&#xff0c;狭义人工智能&#xff0c;指的是一种针对特定任务或领域进行优化的人工智能&#xff0c;例如语音识别、图像识别、自然语言处理、推荐系统 AGI 通用人工智能&#xff0c;强人工智能&#xff0c; ASI 超级人工智能&#xff0c;超人工智…

Erupt框架学习

Erupt框架学习 Erupt框架Erupt简介学习EruptEruptFieldErupt的逻辑删除Erupt的自定义按钮多数据源配置 Erupt框架 Erupt简介 最近因为工作所以接触到了一个低代码框架Erupt。这是一个通用的配置管理框架&#xff0c;主打就是零前端代码&#xff0c;急速开发通用管理框架。 Er…

C# 如何调用python,避免重复造轮子

文章目录 原因资源调用python文件需求解决方案1、C#里面运行python引入python文件&#xff0c;再调用其中的方法启动python脚本&#xff0c;监听返回值改造一下&#xff0c;可以入参的python调用查看是否等待python运行完成之后再运行C#如果参数比较复杂 开一个python网络后端 …

如何用Airtest脚本无线连接Android设备?

1. 前言 之前我们已经详细介绍过如何用AirtestIDE无线连接Android设备&#xff1a; 手把手教你用AirtestIDE无线连接手机&#xff01; &#xff0c;它的关键点在于&#xff0c;需要先 adb connect 一次&#xff0c;才能点击 connect 按钮无线连接上该设备&#xff1a; 但是有很…

​浅谈大型语言模型

大型语言模型&#xff08;Large Language Models&#xff0c;LLMs&#xff09;是一类强大的人工智能模型&#xff0c;具有出色的自然语言处理能力。它们在许多任务中表现出色&#xff0c;如机器翻译、文本摘要、对话生成和情感分析等。下面我们将介绍大型语言模型的训练和生成过…