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-GUI】10 Swing05 JTree
简单的Tree结构: package cn.dzz; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; pub ...
- 【JavaScript】从N个下拉动态监听改变的option值
同事因为这个问题人傻了,是从Ajax请求获取的动态数据遍历的表格 然后表格行的单元格又有下拉选择,有N个下拉,要取出选择的值进行二次请求 <select name="A" i ...
- 【Layui】05 进度条 Progress
文档地址: https://www.layui.com/doc/element/progress.html 演示案例: <div class="layui-progress" ...
- QT基础-弹出框(信息框,模态框,操作框)
学习前端知识的时候就了解到让用户使用的界面一定要足够清晰,因为你永远不知道用户会以何种方式打开你开发的软件,所以莫泰提示框就很重要了.下面将会介绍几本的集中模态对话框,用来提升用户体验! 1.模态框 ...
- C#数据结构与算法实战入门指南
前言 在编程领域,数据结构与算法是构建高效.可靠和可扩展软件系统的基石.它们对于提升程序性能.优化资源利用以及解决复杂问题具有至关重要的作用.今天大姚分享一些非常不错的C#数据结构与算法实战教程,希望 ...
- SMU 2024 spring 天梯赛2
SMU 2024 spring 天梯赛2 7-1 计算指数 - SMU 2024 spring 天梯赛2 (pintia.cn) #include <bits/stdc++.h> usin ...
- 【2】Kaggle 医学影像数据读取
赛题名称:RSNA 2024 Lumbar Spine Degenerative Classification 中文:腰椎退行性病变分类 kaggle官网赛题链接:https://www.kaggle ...
- JavaScript设计模式样例十九 —— 职责链模式
职责链模式(Chain of Responsibility Pattern) 定义:为请求创建了一个接收者对象的链. 目的:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接 ...
- psutil 检测exe是否已经运行
安装依赖 pip install psutil 代码 import psutil def check_if_process_running(process_name): ''' Check if th ...
- FastGPT 正式接入 Flux,准备好迎接 AI 绘画的狂风了么?
Flux 大家最近都听说了吧?它是一款新推出的 AI 绘画模型,拳打 Stable Diffusion 3,脚踢 Midjourney,整个 AI 绘画界都沸腾了. Flux 的主创团队来自由 Sta ...