spring cloud openfeign 源码
一、读取注解信息
入口
1 import org.springframework.boot.SpringApplication;
2 import org.springframework.boot.autoconfigure.SpringBootApplication;
3 import org.springframework.cloud.openfeign.EnableFeignClients;
4
5
6 @SpringBootApplication
7 @EnableFeignClients
8 public class CjsPriceServiceApplication {
9
10 public static void main(String[] args) {
11 SpringApplication.run(CjsPriceServiceApplication.class, args);
12 }
13
14 }
spring boot 项目启动后会自动扫描application上面的注解,@EnableFeignClients的注解如下
1 @Retention(RetentionPolicy.RUNTIME)
2 @Target(ElementType.TYPE)
3 @Documented
4 @Import(FeignClientsRegistrar.class)
5 public @interface EnableFeignClients {
6 。。。。
7 }
在注解中导入了 FeignClientsRegistrar类,用来像spring注册,EnableFeignClients和FeignClient上面开发人员添加的注解信息
1 @Override
2 public void registerBeanDefinitions(AnnotationMetadata metadata,
3 BeanDefinitionRegistry registry) {
4 registerDefaultConfiguration(metadata, registry);
5 registerFeignClients(metadata, registry);
6 }
二、当项目启动,读取@Autowired时会调用,实现了FactoryBean接口的FeignClientFactoryBean.getObject()方法
1 @Override
2 public Object getObject() throws Exception {
3 return getTarget();
4 }
1 <T> T getTarget() {
2 FeignContext context = this.applicationContext.getBean(FeignContext.class);
3 Feign.Builder builder = feign(context);
4
5 if (!StringUtils.hasText(this.url)) {
6 if (!this.name.startsWith("http")) {
7 this.url = "http://" + this.name;
8 }
9 else {
10 this.url = this.name;
11 }
12 this.url += cleanPath();
13 return (T) loadBalance(builder, context,
14 new HardCodedTarget<>(this.type, this.name, this.url));
15 }
16 if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
17 this.url = "http://" + this.url;
18 }
19 String url = this.url + cleanPath();
20 Client client = getOptional(context, Client.class);
21 if (client != null) {
22 if (client instanceof LoadBalancerFeignClient) {
23 // not load balancing because we have a url,
24 // but ribbon is on the classpath, so unwrap
25 client = ((LoadBalancerFeignClient) client).getDelegate();
26 }
27 builder.client(client);
28 }
29 Targeter targeter = get(context, Targeter.class);
30 return (T) targeter.target(this, builder, context,
31 new HardCodedTarget<>(this.type, this.name, url));
32 }
可以看到 getTarget()有两种返回结果的情况,其原理都一样后来调用了 targeter.target()方法
1 package org.springframework.cloud.openfeign;
2
3 import feign.Feign;
4 import feign.Target;
5
6 /**
7 * @author Spencer Gibb
8 */
9 interface Targeter {
10
11 <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
12 FeignContext context, Target.HardCodedTarget<T> target);
13
14 }
默认实现类
1 package org.springframework.cloud.openfeign;
2
3 import feign.Feign;
4 import feign.Target;
5
6 /**
7 * @author Spencer Gibb
8 */
9 class DefaultTargeter implements Targeter {
10
11 @Override
12 public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
13 FeignContext context, Target.HardCodedTarget<T> target) {
14 return feign.target(target);
15 }
16
17 }
然后再看 feign.target(target);方法
1 public <T> T target(Target<T> target) {
2 return build().newInstance(target);
3 }
4
5 public Feign build() {
6 SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
7 new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
8 logLevel, decode404, closeAfterDecode, propagationPolicy);
9 ParseHandlersByName handlersByName =
10 new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
11 errorDecoder, synchronousMethodHandlerFactory);
12 return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
13 }
14 }
build()方法返回了创建代理类的对象,然后调用了创建代理的 newInstance方法
1 public <T> T newInstance(Target<T> target) {
2 Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
3 Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
4 List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
5
6 for (Method method : target.type().getMethods()) {
7 if (method.getDeclaringClass() == Object.class) {
8 continue;
9 } else if (Util.isDefault(method)) {
10 DefaultMethodHandler handler = new DefaultMethodHandler(method);
11 defaultMethodHandlers.add(handler);
12 methodToHandler.put(method, handler);
13 } else {
14 methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
15 }
16 }
17 InvocationHandler handler = factory.create(target, methodToHandler);
18 T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
19 new Class<?>[] {target.type()}, handler);
20
21 for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
22 defaultMethodHandler.bindTo(proxy);
23 }
24 return proxy;
25 }
最后,当我们项目中使用 @Autowired注入时,就回调用工厂类 FeignClientFactoryBean方法的 getObject()方法 返回我们的代理对象
spring cloud openfeign 源码的更多相关文章
- Feign 系列(05)Spring Cloud OpenFeign 源码解析
Feign 系列(05)Spring Cloud OpenFeign 源码解析 [TOC] Spring Cloud 系列目录(https://www.cnblogs.com/binarylei/p/ ...
- api网关揭秘--spring cloud gateway源码解析
要想了解spring cloud gateway的源码,要熟悉spring webflux,我的上篇文章介绍了spring webflux. 1.gateway 和zuul对比 I am the au ...
- 【spring cloud】源码分析(一)
概述 从服务发现注解 @EnableDiscoveryClient入手,剖析整个服务发现与注册过程 一,spring-cloud-common包 针对服务发现,本jar包定义了 DiscoveryCl ...
- Spring Cloud Eureka源码分析 --- client 注册流程
Eureka Client 是一个Java 客户端,用于简化与Eureka Server的交互,客户端同时也具备一个内置的.使用轮询负载算法的负载均衡器. 在应用启动后,将会向Eureka Serve ...
- Spring Cloud Eureka源码分析之服务注册的流程与数据存储设计!
Spring Cloud是一个生态,它提供了一套标准,这套标准可以通过不同的组件来实现,其中就包含服务注册/发现.熔断.负载均衡等,在spring-cloud-common这个包中,org.sprin ...
- 【Day03】Spring cloud:源码讲解与容器化初探
今日内容 原理和源码 容器化过度 一.Naocs 1.介绍 server端 启动入口类(Spring Boot项目,提供8848端口的监听访问) 源码包含InstanceController类(ser ...
- spring cloud ribbon源码解析(一)
我们知道spring cloud中restTemplate可以通过服务名调接口,加入@loadBalanced标签就实现了负载均衡的功能,那么spring cloud内部是如何实现的呢? 通过@loa ...
- Spring Cloud Ribbon 源码分析---负载均衡算法
上一篇分析了Ribbon如何发送出去一个自带负载均衡效果的HTTP请求,本节就重点分析各个算法都是如何实现. 负载均衡整体是从IRule进去的: public interface IRule{ /* ...
- Spring Cloud Zuul源码
一.Zuul源码分析(初始化流程.请求处理流程)
- Spring Cloud Ribbon源码分析---负载均衡实现
上一篇结合 Eureka 和 Ribbon 搭建了服务注册中心,利用Ribbon实现了可配置负载均衡的服务调用.这一篇我们来分析Ribbon实现负载均衡的过程. 从 @LoadBalanced入手 还 ...
随机推荐
- Java jdk版本对照表
这里将JDK版本和major.minor的版本的对照关系进行整理,作为今后查阅的依据. 序号 jdk版本 major.minor version 1 1.1 45 2 1.2 46 3 1.3 47 ...
- Sealos 就是小团队的神器
作者:阳明.Kubernetes 布道师,公众号 K8s 技术圈主理人 最近我们新开发了一个项目 fastclass.cn,这个项目是一个独立开发者的学习网站,我们的目标是帮助你使用 Figma.Py ...
- 安卓如何设置开机启动某个程序?init.rc给你搞定
一.如何设置开机启动某个程序? 1.需求描述 最近有个项目需要在Android开机启动之后,自动执行一个C语言编写的程序:pengd 该程序运行时需要修改网络ip地址及其他网络操作,所以需要root权 ...
- python3安装虚拟环境并使用freeze命令迁移模块
python3安装虚拟环境 #1.安装虚拟环境 pip3 install virtualenv #2.创建虚拟环境 python3 -m venv venv #或者 python3 -m venv . ...
- zabbix资产清单inventory管理
概述 监控的设备越来越多,有时候搞不清楚哪台服务器是什么配置,大多公司有自己的资产清单,要去专门的系统查询显得多少有点麻烦.为此,zabbix专门设置了设备资产管理功能.我们创建或者编辑主机的时候,可 ...
- LaTeX 常见希腊字母
字母名称 大写 命令 小写 命令 alpha A A α \alpha beta B B β \beta gamma Γ \Gamma γ \gamma delta Δ \Delta δ \delta ...
- Java面试集锦(一)
计算机网络 摘要:1. 在浏览器中输入url地址 显示主页的过程,整个过程会使用哪些协议 image.jpeg总体来说分为以下几个过程: DNS解析 TCP连接 发送HTTP请求 服务器处理请求并返回 ...
- python pyqt6 QMenu 设定圆角边框
本来这个没有必要写,但是因为写的过程中,按照网上的写法运行,不知道为什么QMenu的右下角有圆角边框与直角背景颜色会覆盖显示 所以还是有必要写一下 menu = QMenu(self.tool_but ...
- 使用win-acme在windows+iis服务器下配置自动续期SSL证书【转】
发现阿里云免费证书只有3个月有效期了,手动操作太麻烦,咨询阿里云客服,阿里云说这是大势所趋,遂转向其他云,后来发现百度云还有1年的免费证书,继续问阿里云客服,其他友商都还在免费1年的,为啥阿里云免费的 ...
- C++:使自定义类支持迭代器
概述 在 C++ 中,链表迭代器是一种用来遍历链表(如 std::list)元素的工具.链表是一种数据结构,其中每个元素(节点)包含一个数据值和一个指向下一个节点的指针.链表迭代器允许以类似于数组的方 ...