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()方法 返回我们的代理对象

原文地址:https://www.cnblogs.com/yechen2019/p/11676859.html

时间: 2024-10-28 04:17:25

spring cloud openfeign 源码的相关文章

Feign 系列(05)Spring Cloud OpenFeign 源码解析

Feign 系列(05)Spring Cloud OpenFeign 源码解析 [TOC] Spring Cloud 系列目录(https://www.cnblogs.com/binarylei/p/11563952.html#feign) 在 上一篇 文章中我们分析 Feign 参数解析的整个流程,Feign 原生已经支持 Feign.JAX-RS 1/2 声明式规范,本文着重关注 Spring Cloud 是如果整合 OpenFeign 的,使之支持 Spring MVC? 1. Sprin

spring cloud ribbon源码解析(一)

我们知道spring cloud中restTemplate可以通过服务名调接口,加入@loadBalanced标签就实现了负载均衡的功能,那么spring cloud内部是如何实现的呢? 通过@loadBalanced我们进入标签 注释解释这个标签是标记为restTemplate,作为loadBalancerClient,接着去看loadBalancerClient loadBalancerClient通过继承serviceInstanceChooser,主要包含以下几个抽象方法: 1.choo

Spring Cloud Ribbon 源码分析---负载均衡算法

上一篇分析了Ribbon如何发送出去一个自带负载均衡效果的HTTP请求,本节就重点分析各个算法都是如何实现. 负载均衡整体是从IRule进去的: public interface IRule{ /* * choose one alive server from lb.allServers or * lb.upServers according to key * * @return choosen Server object. NULL is returned if none * server i

Spring Cloud Ribbon源码分析---负载均衡实现

上一篇结合 Eureka 和 Ribbon 搭建了服务注册中心,利用Ribbon实现了可配置负载均衡的服务调用.这一篇我们来分析Ribbon实现负载均衡的过程. 从 @LoadBalanced入手 还记得前面配置 RestTemplate: @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } 在消费端使用Spring 提供的 RestTemplate 来发出请求,而Ribbon 在 Rest

【spring cloud】源码分析(一)

概述 从服务发现注解 @EnableDiscoveryClient入手,剖析整个服务发现与注册过程 一,spring-cloud-common包 针对服务发现,本jar包定义了 DiscoveryClient 接口 public interface DiscoveryClient { /** * A human readable description of the implementation, used in HealthIndicator * @return the description

Spring Cloud Eureka源码分析---服务注册

本篇我们着重分析Eureka服务端的逻辑实现,主要涉及到服务的注册流程分析. 在Eureka的服务治理中,会涉及到下面一些概念: 服务注册:Eureka Client会通过发送REST请求的方式向Eureka Server注册自己的服务,提供自身的元数据,比如 IP 地址.端口.运行状况指标的URL.主页地址等信息.Eureka Server接收到注册请求后,就会把这些元数据信息存储在一个ConcurrentHashMap中. 服务续约:在服务注册后,Eureka Client会维护一个心跳来持

Spring Security 解析(七) —— Spring Security Oauth2 源码解析

Spring Security 解析(七) -- Spring Security Oauth2 源码解析 ??在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决定先把Spring Security .Spring Security Oauth2 等权限.认证相关的内容.原理及设计学习并整理一遍.本系列文章就是在学习的过程中加强印象和理解所撰写的,如有侵权请告知. 项目环境: JDK1.8 Spring boot 2.x Spring Security

Spring mvc之源码 handlerMapping和handlerAdapter分析

Spring mvc之源码 handlerMapping和handlerAdapter分析 本篇并不是具体分析Spring mvc,所以好多细节都是一笔带过,主要是带大家梳理一下整个Spring mvc的执行流程,以及如何根据URL查找处理器Controller的实现 (适合那些刚阅读源码不知道如何下手的人) http://www.guojinbao.com/borrow/borrowDetail/GETadLPjnf0[d].do 如何根据URL地址---->找到正确处理器Controller

spring 事件模式 源码导读

一,jdk 事件对象基类 package java.util; import java.io.Serializable; public class EventObject implements Serializable { protected transient Object source; public Object getSource() { return this.source; } public EventObject(Object paramObject) { if (paramObj