1 架构图。

2 feign的初始化扫包原理。

(1)feign使用,是main上的@EnableFeignClients 和 api的@FeignClient(value = "serviceXXX") 搭配使用。

(2)@FeignClient 是个自定义注解没啥东西只是个feign定义,

(3)@EnableFeignClients核心是@Import(FeignClientsRegistrar.class),在这里完成对@FeignClient的扫描和beanDefination的定义。

3 feign扫包和注册细节

(1)FeignClientsRegistrar的核心方法 registerBeanDefinitions(),包含

registerDefaultConfiguration(metadata, registry); 拿到@EnableFeignClients的属性冰注册配置bean,

registerFeignClients (metadata, registry); 扫@feignClient并注册,是核心

(2)registerFeignClients细节,

a 得到scanner:ClassPathScanningCandidateComponentProvider

b 根据getBasePackages()得到包,默认是SpringbootApplication同路径的包。

c 声明FeignClient.class的AnnotationTypeFilter,加入到scanner

d 遍历packages,findCandidateComponents(),通过判断isCandidateComponent拿到class,判断依据是是否满足注解filter(已经加入FeignClient条件)

e registerFeignClient 注册得到的feign的bd,是用factorybean,FeignClientFactoryBean,扩展了很多feign属性。beanname是feign类的全类名。最终register到容器。

4 FeignClientFactoryBean 解析

(1)通过getObject()返回bean,调用getTarget()

(2)首先FeignContext context = applicationContext.getBean(FeignContext.class); 拿到feign环境,bean定义是在org.springframework.cloud.openfeign.FeignAutoConfiguration, 核心this.configurations.put(client.getName(), client) 是为每个feign维护了一个环境,放在map中。每个feign实例都能从feignContext里拿到独立的spring容器。T instance = context.getInstance(this.name, type);这种,name就是feignclient注解的 “servicexxxx”。

(3)Feign.Builder builder = get(context, Feign.Builder.class),结合环境生成一个builder,

这个builder也是从spring容器拿的,FeignClientsConfiguration中有两个,一个hystrix的,一个retryer(默认)的。从feignContext里拿到servicename对应的容器,再根据类型拿到Encoder、Decoder、Contract设置builder。这些bean都在FeignClientsConfiguraiton中定义:SpringEncoder、ResponseEntityDecoder、SpringMvcContract

configureFeign(),把application.yml的属性配置进builder中,

(4)核心,处理url后,手动写一个HardCoudeTarget,包含服务名称、接口类名、url,调用loadBalance(target),在这里面通过容器拿到一个Client,client定义在DefaultFeignLoadBalancedConfiguration,实际类型是LoadBalancerFeignClient。

(5)targeter.target(this, builder, context, target) 实现代理。

5 代理的实现过程。

Feign.Builder和HardCodedTarget,来最终基于feign的动态代理。

(1) build().newInstance(target);

build()融合了FeignBuilder所有内容创建了RefrectiveFeign,先创建SynchronousMethodHandler.Factory,包含LoadBalancerFeignClient、Retryer(负责请求重试)、请求拦截器、日志打印等,用来创建methodHandler。

(2)Map nameToHandler = targetToHandlersByName.apply(target);

根据contract,解析target里面所有方法,包含属性和各种springmvc注解解析,形成SynchronousMethodHandler

(3)Map methodToHandler = new LinkedHashMap();

遍历target的method,形成method和SynchronousMethodHandler的对应map。

(4)InvocationHandler handler = factory.create(target, methodToHandler)-》ReflectiveFeign.FeignInvocationHandler(target, dispatch)  形成代理。最终是SynchronousMethodHandler的invoke方法,实现最终Proxy.newProxyInstance代理过程。

(5)invoke方法: dispatch.get(method).invoke(args) 根据方法本身,拿到MethodHandler,调用MethodHandler的invoke,包含了ribbon的RequestTemplate,负载均衡,融合重试机制。

6 代理invoke的实际执行过程

(1)核心在FeignInvocationHandler的invoke,dispatch.get(method).invoke(args);实际是SynchronousMethodHandler的invoke,进而executeAndDecode(template);

(2)    Request request = targetRequest(template); 得到request,其实就是target的feignService信息(service名称,类型等)和请求的springmvc方法,结合出

“GET http://service2/serviceInfo HTTP/1.1”这种请求信息。

(3)response = client.execute(request, options);是LoadBalanceFeignClient,先创建一个RibbonRequest,在拿到ribbon的IClientConfig。

(4)lbClient(clientName),从CachingSpringLoadBalancerFactory中拿到FeignLoadBalancer,FeignLoadBalancer里通过spring容器拿到并封装了ribbon的ILoadBalancer(ribbon用的ZoneAwareLoadBalancer)。CachingSpringLoadBalancerFactory采用了缓存。

(5)lbClient(clientName).executeWithLoadBalancer(ribbonRequest,requestConfig).toResponse() 的第二步

executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();

调用路线:submit()->selectServer()->ServerOption.call() 发送http请求。selectServer使用了ribbon的select过程。

7 feign的编解码方式

HttpMessageConverters 默认使用jackson2方式进行序列化和反序列化。但是如果是微服务间频频通信,使用jackson2序列化和反序列化会占用不少系统资源,并且效率较差。可以手动扩展编解码方式,继承AbstractHttpMessageConverter ,使用@FeignClient(value = "service",path ="/nafosRemoteCall/test" , configuration = ProtoFeignConfiguration.class) 进行配置。

feign扫描_feign原理+源码解析相关推荐

  1. c++ socket线程池原理_ThreadPoolExecutor线程池实现原理+源码解析

    推荐学习 被微服务轰炸?莫怕!耗时35天整出的「微服务学习教程」送你 死磕「并发编程」100天,全靠阿里大牛的这份最全「高并发套餐」 闭关28天,奉上[Java一线大厂高岗面试题解析合集],备战金九银 ...

  2. 集合深度学习07—Set、HashSet、LinkedHashSet、TreeSet、 底层原理 源码解析

    一.Set接口 特点: 唯一 无序(相对List接口部分来说的,无序不等于随机) 没有索引相关的方法 遍历方式: 迭代器 增强 for 循环(底层还是 Itr 迭代器) 二.HashSet 1. Ha ...

  3. SpringBoot入门-源码解析(雷神)

    一.Spring Boot入门 视频学习资料(雷神): https://www.bilibili.com/video/BV19K4y1L7MT?p=1 github: https://github.c ...

  4. 并发编程与源码解析 (三)

    并发编程 (三) 1 Fork/Join分解合并框架 1.1 什么是fork/join ​ Fork/Join框架是JDK1.7提供的一个用于并行执行任务的框架,开发者可以在不去了解如Thread.R ...

  5. Alibaba-AndFix Bug热修复框架原理及源码解析

    小憩之后,继续为你解读AndFix热修复框架,呵呵. 上一篇Alibaba-AndFix Bug热修复框架的使用已经介绍了AndFix的使用,这篇主要介绍AndFix原理以及源码解析. AndFix原 ...

  6. Mybatis运行原理及源码解析

    Mybatis源码解析 一.前言 本文旨在mybatis源码解析,将整个mybatis运行原理讲解清楚,本文代码地址: https://github.com/lchpersonal/mybatis-l ...

  7. Dubbo 实现原理与源码解析系列 —— 精品合集

    摘要: 原创出处 http://www.iocoder.cn/Dubbo/good-collection/ 「芋道源码」欢迎转载,保留摘要,谢谢! 1.[芋艿]精尽 Dubbo 原理与源码专栏 2.[ ...

  8. 【详解】Ribbon 负载均衡服务调用原理及默认轮询负载均衡算法源码解析、手写

    Ribbon 负载均衡服务调用 一.什么是 Ribbon 二.LB负载均衡(Load Balancer)是什么 1.Ribbon 本地负载均衡客户端 VS Nginx 服务端负载均衡的区别 2.LB负 ...

  9. libev源码解析——定时器原理

    本文将回答<libev源码解析--I/O模型>中抛出的两个问题.(转载请指明出于breaksoftware的csdn博客) 对于问题1:为什么backend_poll函数需要指定超时?我们 ...

最新文章

  1. AC日记——丑数 codevs 1246
  2. 小米12 Ultra延期发布:或与小米MIX Fold 2折叠屏旗舰同台亮相
  3. 概率论:集合、假设检验、分布、矩阵、估计
  4. QOS 令牌桶实现代码1
  5. Atitit vod ver 12 new feature v12 pb2 影吧 视频 电影 点播 播放系统v12新特性
  6. 怎么使用阿里巴巴矢量图标
  7. 平均值绝对偏差最大c语言,请教平均值和最大偏差值得使用
  8. Vue使用axios图片上传报错500
  9. word2003流程图变成图片_流程图怎么画word2003
  10. 华为手机相册怎么镜像翻转_手机相册里的照片误删怎么恢复?简单操作就搞定...
  11. 与繁重的工作一起修行
  12. 美式口语发音技巧:《发音总结》
  13. Chrome浏览器上传图片或图片另存时浏览器无响应
  14. 星淘惠告诉你跨境平台那么多,凭什么要选亚马逊?
  15. python 异步io 写excel_python异步IO编程(二)
  16. 咨询案例:再来几种利益相关人地图
  17. 厦大C语言上机 1367 几何级数的计算机验证法
  18. Linux tar 命令 将归档内指定文件解压到指定目录
  19. Android面试 谈谈https原理
  20. node.js+vue+elementui餐厅外卖团购点餐限时秒杀网站平台

热门文章

  1. 厘清大数据要点,技术成长不迷茫
  2. U^2 Net显著性检测分割抠图
  3. Ubuntu20.04创建虚拟网卡
  4. 计算机毕业设计Java固定资产管理系统(源码+系统+mysql数据库+Lw文档)
  5. 计算机组成原理名词解释
  6. win10 快捷键大全
  7. 黑马程序员_抽象类和接口
  8. 程序员与代码的搞笑日常
  9. iOS学习笔记2(结合项目)--Category和Extension的区别
  10. python批量读取grib_python读取grib2文件