<
>

Spring Cloud OpenFeign 远程调用

2022-08-22 10:44:02 来源:易采站长站 作者:

目录
一、什么是Feign?二、????理解远程调用三、OpenFeign和Feign的区别四、OpenFeign核心工作原理五、OpenFeign包扫描原理六、总结

一、什么是Feign?

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

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

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

二、????理解远程调用

    本地调用(Local>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>

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

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

    四、OpenFeign核心工作原理

      通过>@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)>
        @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>

暂时禁止评论

微信扫一扫

易采站长站微信账号