Feign学习笔记2-源码解读

本文深入探讨了Feign的源码组成及其实现原理,详细分析了Feign从社区、Netflix到Spring的不同来源,并介绍了核心组件如ReflectiveFeign、RequestTemplate及InvocationHandlerFactory的作用流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Feign源码简介

spring-cloud-netflix-Feign,这个是Feign的全名。Spring官网上是没有Feign这个项目存在的,Feign是作为netflix的一个子项目存在。
netflix包涵Eureka、Zuul、Ribbon、Feign、Hystrix、Hystrix Dashboard、Turbine。
曾经一度把netflix与Spring cloud等同,用的全部都是netflix中的东西。后来接触config与bus后才将netflix与cloud分开。然后,我就认识了一个叫netflix的影片租赁公司。

feign源码来源

我们目前所使用的feign来自于3个部分,或者说2个部分。
第一个部分是来自社区的open-feign。具体来源是 Netflix还是社区未验证。
第二个部分是 Netflix的封装。
第三个部分是来自于Spring的封装。
实际上大伙也就知道feign呢和那个影片租赁公司 Netflix脱不开关系就是了。以上三个来源最终变成了
1. org.springframework.cloud:spring-cloud-netflix-core
2. io.github.openfeign:feign-core

netflix自从加入了spring后代码被改的天翻地覆,所以想看第二部分来自于netflix的代码的话估计要看spring-cloud-netflix-core较老的版本才行了。

feign-core解读

首先将所有标签全部忽略掉,因为一个都没有用到。
然后还剩下几个关键的是
1. Client(接口) - Feign(抽象类) - ReflectiveFeign(实现类)。
2. RequestTemplate
3. InvocationHandlerFactory(接口) - SynchronousMethodHandler(实现类)
4. Decoder与Encoder

调用栈大约如下
1. ReflectiveFeign 被反射实例化
2. 调用ReflectiveFeign.invoke
3. 调用SynchronousMethodHandler.invoke。此处实例化RequestTemplate
4. 调用SynchronousMethodHandler.executeAndDecode
5. 将RequestTemplate build为request,调用http客户端执行
6. 将Response Decode为Object并返回

open-feign并不是主题,就不贴代码图了,反正github上面有。后续会去研究研究原生的open-feign如何去玩的。

spring-cloud-netflix-core解读

这个玩意比较坑爹,因为看了feign就意味你必须去看其他的代码。你看到fegin包下存在诸如fegin.ribbon、HystrixTargeter等等字样就知道已经分不开了。

来自于Spring MVC的影响

不论其他了,自从netflix加入spring-cloud大家庭之后,第一个变化就是@RequestMapping、@RequestParam等来自于spirng mvc的注释。他们在feign中被重写,而且拥有与Spring mvc相同的语义,语法。但是细节却不一样,需要谨慎对待。
重写语法的注释有

  • AnnotatedParameterProcessor接口

    • PathVariableParameterProcessor 重写 PathVariable
    • RequestHeaderParameterProcessor 重写 RequestHeader
    • RequestParamParameterProcessor 重写 RequestParam

    让我非常纳闷的是RequestMapping效果也是不一样的,没有找到重写的地方,比较纳闷怎么达到这个效果的。

标签用法SpringMVCfeign
RequestParam不写name默认使用字段名称报错
待完成

ribbon的乱入

说是乱入,真的是乱入,这个代码曾经误导我好久。上面写过了feign-core的关键代码中有一个接口Client。我曾经一度认为它是使用的默认的Default实现。

package feign;
public interface Client {
    Response execute(Request var1, Options var2) throws IOException;

    public static class Default implements Client {
        private final SSLSocketFactory sslContextFactory;
        private final HostnameVerifier hostnameVerifier;

        public Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
            this.sslContextFactory = sslContextFactory;
            this.hostnameVerifier = hostnameVerifier;
        }
        ....

但是,实际上是使用的ribbon的一个实现

package org.springframework.cloud.netflix.feign.ribbon;
public class LoadBalancerFeignClient implements Client {
    static final Options DEFAULT_OPTIONS = new Options();
    private final Client delegate;
    private CachingSpringLoadBalancerFactory lbClientFactory;
    private SpringClientFactory clientFactory;

    public LoadBalancerFeignClient(Client delegate, CachingSpringLoadBalancerFactory lbClientFactory, SpringClientFactory clientFactory) {
        this.delegate = delegate;
        this.lbClientFactory = lbClientFactory;
        this.clientFactory = clientFactory;
    }

    public Response execute(Request request, Options options) throws IOException {
        try {
            URI asUri = URI.create(request.url());
            String clientName = asUri.getHost();
            URI uriWithoutHost = cleanUrl(request.url(), clientName);
            RibbonRequest ribbonRequest = new RibbonRequest(this.delegate, request, uriWithoutHost);
            IClientConfig requestConfig = this.getClientConfig(options, clientName);
            ....

看完这里我就突然明白为啥在FeignClient中的name一定要写serverName了。都是因为这个实现。所以,想使用直连的方式只需要把这个实现类顶替掉就好了……..
在更换okHttp的时候试验完成,不配置ribbon就可以使用ip+port直连。

待续

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值