Feign学习笔记2-源码解读

来源:互联网 发布:js offsetwidth取不到 编辑:程序博客网 时间:2024/06/16 19:38

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效果也是不一样的,没有找到重写的地方,比较纳闷怎么达到这个效果的。

标签 用法 SpringMVC feign 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直连。

待续