Spring Cloud OpenFeign 远程调用

 更新时间:2022年08月22日 09:13:46   作者:austin  
这篇文章主要介绍了Spring Cloud OpenFeign 远程调用,本文通过远程调用的GitHub开放API用到的OpenFeign作为示例代码作为入口进行讲解。然后以图解+解读源码的方式深入剖析了OpenFeign的运行机制和架构设计,需要的朋友可以参考一下

一、什么是Feign?

Feign makes writing java http clients easier,这是官方给出的一个说明,本意翻译是:Feign使编写Java http客户端更容易,Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,Feign可以通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求。

Feign封装了Http调用流程,更适合面向接口化的编程习惯。

在服务调用的场景中,我们经常调用基于Http协议的服务,而我们经常使用到的远程调用框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Forest、Netty等等,这些框架在基于自身的专注点提供了自身特性。而从角色划分上来看,他们的职能是一致的提供Http调用服务。

二、💭理解远程调用

  • 本地调用(Local Procedure Call,简称LPC
  • 远程调用(Remote Procedure Call,简称RPC

feign主要是为我们提供了远程调用的服务,那么什么是远程调用呢? 远程调用说白了可以理解为不同服务之间方法的调用,实质上是两台主机间的网络通信 ,涉及到网络通信又必然会有序列化、反序列化,编解码等一些必须要考虑的问题,现在业界内比较流行的一些 RPC 框架,例如:Dubbo提供的是基于接口的远程方法调用,通过rpc远程调用框架,客户端只需要知道接口的定义即可调用远程服务。

而 feign主要就是用来简化我们发起远程调用的代码,以一个远程调用Github开放的API为🌰:

/**
 * GitHub客户端GitHubFeign,访问GitHub开发平台API,开放平台API地址:https://www.apifox.cn/apihub/
 *
 * @author: jacklin
 * @date: 2022/6/30 21:20
 */
@FeignClient(name = "github-client", url = "https://api.github.com")
public interface GitHubFeign {


    /**
     * 查找github标准库信息
     * <p>
     * https://api.github.com/search/repositories   v
     *
     * @author: jacklin
     * @since 2022/6/30 21:27
     **/
    @GetMapping(value = "/search/repositories", produces = MediaType.APPLICATION_JSON_VALUE)
    String searchRepositories(@RequestParam("q") String q);
}

第一步: Maven pom文件中引入 OpenFeign 组件。

第二步:客户端需要定义一个GitHubFeign接口,里面定义一个searchRepositories()方法,可以看到这个接口上添加了@FeignClient注解,而括号里面指定了服务名:github-client,显示声明这个接口是用来远程调用GitHub API服务的,url用来指定调用服务的全路径,其他方法路径前缀必须与url地址一致,完整的请求路径URL地址:https://api.github.com/search/repositories

第三步:需要在服务启动类添加@EnableFeignClients注解,在服务启动时,Spring扫描被@FeignClints修饰的接口,基于动态代理生成本地JDK Proxy代理对象实例,然后将这些代理实例注册到Spring IOC容器中,当远程接口被调用时,由Proxy代理实例去完成真正的远程访问,并返回结果。

第四步:在Controller引入GitHubFeign服务,完成远程服务调用:

@RestController
@RequestMapping(value = "/github", produces = MediaType.APPLICATION_JSON_VALUE)
public class GithubController {

    @Resource
    private GitHubFeign gitHubFeign;

    /**
     * 查找github标准库信息
     *
     * @author: jacklin
     * @since 2022/6/30 21:36
     **/
    @GetMapping(value = "/searchRepositories")
    String searchRepositories(@RequestParam(value = "q") String q) {
        return gitHubFeign.searchRepositories(q);
    }
}

返回结果数据如下👉:

可以看出,feign使得远程调用跟本地方法是一样,极大的简化了rpc远程调用的方式。

三、OpenFeign和Feign的区别

可以认为OpenFeign是Feign的增强版,不同的是OpenFeign支持Spring MVC注解

FeignOpenFeign
Feign是Netflix公司写的,是SpringCloud组件中的一个轻量级RESTful的HTTP服务客户端,是SpringCloud中的第一代负载均衡客户端。OpenFeign的前身是Neflix Feign,Spring Cloud在Feign的基础上扩展支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

OpenFeignFeign底层都内置了Ribbon负载均衡组件,在导入OpenFeign依赖后无需专门导入Ribbon依赖,用做客户端负载均衡,去调用注册中心服务。

四、OpenFeign核心工作原理

  • 通过 @EnableFeignCleints触发Spring应用程序对classpath中@FeignClient修饰类的扫描。
  •  解析到 @FeignClient 修饰类后,Feign框架通过扩展Spring Bean Deifinition的注册逻辑,最终注册一个FeignClientFacotoryBean进入Spring容器
  •  Spring容器在初始化其他用到 @FeignClient 接口的类时, 获得的是FeignClientFacotryBean产生的一个代理对象Proxy
  •  基于Java原生的动态代理机制,针对Proxy的调用,都会被统一转发给Feign框架所定义的一个 InvocationHandler,由该Handler完成后续的HTTP转换,发送、接收以及HTTP响应的工作。

五、OpenFeign包扫描原理

要想通过OpenFeign实现远程调用,就涉及到一个OpenFeign的核心注解:@EnableFeignClient,根据字面意思可以知道,该注解是开启OpenFeign的功能,一般都会被添加到我们的启动类上。

Spring包扫描的大体流程:

  • 开启OpenFeign功能@EnableFeignClients,接着通过@Import(FeignClientsRegistrar.class) 这个import的方式导入FeignClientsRegistrar类,开启OpenFeign组件的加载。
@SpringBootApplication
@EnableFeignClients
public class MambaBlockDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MambaBlockDemoApplication.class, args);
    }
}

FeignClientsRegistrar负责Feign接口的加载,源码如下:

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
   //注册配置
   registerDefaultConfiguration(metadata, registry);
   //注册FeignClient
   registerFeignClients(metadata, registry);
}
  • registerFeignClients()方法会调用findCandidateComponents()方法来查找指定路径的basePackages下所有被@FeignClients注解修饰的类、接口。
LinkedHashSet<BeanDefinition> candidateComponents = Set<BeanDefinition> findCandidateComponents(String basePackage)
  • 只保留被@FeignClient的修饰的接口。
for (BeanDefinition candidateComponent : candidateComponents) {
   if (candidateComponent instanceof AnnotatedBeanDefinition) {
      // verify annotated class is an interface
      AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
      AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
      Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");

      Map<String, Object> attributes = annotationMetadata
            .getAnnotationAttributes(FeignClient.class.getCanonicalName());

      String name = getClientName(attributes);
      registerClientConfiguration(registry, name, attributes.get("configuration"));
      //注入到Spring容器中
      registerFeignClient(registry, annotationMetadata, attributes);
   }
}

六、总结

本文通过远程调用的GitHub开放API用到的OpenFeign作为示例代码作为入口进行讲解。然后以图解+解读源码的方式深入剖析了OpenFeign的运行机制和架构设计

到此这篇关于Spring Cloud OpenFeign 远程调用的文章就介绍到这了,更多相关Spring Cloud OpenFeign 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用MultipartFile实现文件上传功能

    利用MultipartFile实现文件上传功能

    这篇文章主要为大家详细介绍了利用MultipartFile实现文件上传功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • Mybatis与微服务注册的详细过程

    Mybatis与微服务注册的详细过程

    这篇文章主要介绍了Mybatis与微服务注册,主要包括SpringBoot整合MybatisPlus,SpringBoot整合Freeamarker以及SpringBoot整合微服务&gateway&nginx的案例代码,需要的朋友可以参考下
    2023-01-01
  • SpringBoot深入了解日志的使用

    SpringBoot深入了解日志的使用

    Spring Boot默认使用SLF4J+Logback 记录日志,并提供了默认配置,即使我们不进行任何额外配,也可以使用SLF4J+Logback进行日志输出
    2022-07-07
  • java打包解包操作小结

    java打包解包操作小结

    使用别人的jar包程序,需要修改其中的相关参数然后重新打包,在此记录一下打包和解包过程,感兴趣的朋友跟随小编一起看看吧
    2023-10-10
  • Java根据表达式获取对象中的值及设置值的例子

    Java根据表达式获取对象中的值及设置值的例子

    这篇文章主要介绍了Java根据表达式获取对象中的值及设置值的例子,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-03-03
  • 浅谈js文件引用方式及其同步执行与异步执行

    浅谈js文件引用方式及其同步执行与异步执行

    下面小编就为大家带来一篇浅谈js文件引用方式及其同步执行与异步执行。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • java中实现一个定时任务的方式

    java中实现一个定时任务的方式

    本文介绍了三种在Java中实现定时任务的方法,并推荐使用Spring Boot注解方式,介绍了如何使用`@Scheduled`注解结合Cron表达式来设置定时任务,并提供了一个示例配置文件
    2025-03-03
  • Java中Thread类基本用法详解

    Java中Thread类基本用法详解

    Java中的Thread类是用于创建和管理线程的类,Thread类提供了许多方法来管理线程,包括启动线程、中断线程、暂停线程等,下面这篇文章主要给大家介绍了关于Java中Thread类基本用法的相关资料,需要的朋友可以参考下
    2023-06-06
  • 关于eclipse中运行tomcat提示端口被占用的4种解决

    关于eclipse中运行tomcat提示端口被占用的4种解决

    这篇文章主要介绍了关于eclipse中运行tomcat提示端口被占用的4种解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Java中的Semaphore计数信号量详细解析

    Java中的Semaphore计数信号量详细解析

    这篇文章主要介绍了Java中的Semaphore计数信号量详细解析,Semaphore 是一个计数信号量,必须由获取它的线程释放,常用于限制可以访问某些资源的线程数量,例如通过 Semaphore 限流,需要的朋友可以参考下
    2023-11-11

最新评论