写点什么

Feign 的整体流程

作者:周杰伦本人
  • 2022-10-19
    贵州
  • 本文字数:2113 字

    阅读完需:约 1 分钟

Feign 的整体流程

作用

feign 的作用就是根据 RPC 远程调用的接口生成动态代理实例,然后根据 SpringMVC 中的方法上的注解生成方法处理器,最终生成 HTTP 请求,通过 feignClient 发送给服务端。

整体流程

feign 的整体流程:

FeignClientsRegistrar 的 registerFeignClient()方法

在启动类添加注解 @EnableFeignClients,这个注解中导入了 FeignClientsRegistrar 类,FeignClientsRegistrar 类的主要功能就是通过扫描 @FeignClient 注解创建 FeignClientFactoryBean 实例,然后注入到 Spring 容器中。


private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {        String className = annotationMetadata.getClassName();        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);        this.validate(attributes);        definition.addPropertyValue("url", this.getUrl(attributes));        definition.addPropertyValue("path", this.getPath(attributes));        String name = this.getName(attributes);        definition.addPropertyValue("name", name);        definition.addPropertyValue("type", className);        definition.addPropertyValue("decode404", attributes.get("decode404"));        definition.addPropertyValue("fallback", attributes.get("fallback"));        definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));        definition.setAutowireMode(2);        String alias = name + "FeignClient";        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();        boolean primary = (Boolean)attributes.get("primary");        beanDefinition.setPrimary(primary);        String qualifier = this.getQualifier(attributes);        if (StringUtils.hasText(qualifier)) {            alias = qualifier;        }
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias}); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); }
复制代码

getTarget()方法

然后代码中通过 @Resource 等注解使用的时候,会通过 FeignClientFactoryBean 的 getObject()方法来获取到动态代理对象。动态代理对象的生成是通过 Feign.Builder 的 target 方法中调用 build()方法生成 ReflectiveFeign 的实例,然后通过 newInstance 创建最终的 RPC 动态代理的实例。


<T> T getTarget() {        FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class);        Builder builder = this.feign(context);        String url;        if (!StringUtils.hasText(this.url)) {            if (!this.name.startsWith("http")) {                url = "http://" + this.name;            } else {                url = this.name;            }
url = url + this.cleanPath(); return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, url)); } else { if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) { this.url = "http://" + this.url; }
url = this.url + this.cleanPath(); Client client = (Client)this.getOptional(context, Client.class); if (client != null) { if (client instanceof LoadBalancerFeignClient) { client = ((LoadBalancerFeignClient)client).getDelegate(); }
builder.client(client); }
Targeter targeter = (Targeter)this.get(context, Targeter.class); return targeter.target(this, builder, context, new HardCodedTarget(this.type, this.name, url)); } }
复制代码

动态代理的创建

创建动态代理实例的时候,feign 会先创建一个调用处理器,然后每个方法创建方法处理器,方法处理器缓存在调用处理器的 dispatch 集合中。动态代理实例进行方法调用的时候,Feign 根据反射实例从调用处理器的 dispatch 集合中找到对应的方法处理器,然后进行 Http 请求。方法处理器生成 Request 请求,然后交给 feign 的客户端进行调用,真正使用的时候用 LoadBalancerFeignClient,因为它可以进行负载均衡,它还会委托具体的 client 完成 http 请求。

总结

这篇文章主要讲了 Feign 的整体流程,主要是通过 @EnableFeignClients 注解引入 FeignClientsRegistrar 类,类中扫描 @FeignClient 注解,注入 FeignClientFactoryBean 实例,通过 getObject()方法获取动态实例,Feign 的远程调用实际上就是通过动态代理来完成的,动态代理的创建是 feign 根据利用反射机制创建代理对象,然后找到对应的方法处理器发起 http 请求

发布于: 刚刚阅读数: 4
用户头像

还未添加个人签名 2020-02-29 加入

公众号《盼盼小课堂》,多平台优质博主

评论

发布
暂无评论
Feign的整体流程_10月月更_周杰伦本人_InfoQ写作社区