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直连。