所有文章

https://www.cnblogs.com/lay2017/p/11908715.html

正文

openfeign是一种声明式的webservice客户端调用框架。你只需要声明接口和一些简单的注解,就能像使用普通的Bean一样调用远程服务。本文将了解一下openfeign自动配置相关的东西,看看都做了哪些东西。

@EnableFeignClients开启openfeign

首先,我们从@EnableFeignClients这个开关注解开始了解。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients { // ...省略配置
}

这个注解导入了一个类FeignClientsRegistrar,这个类实现了ImportBeanDefinitionRegistrar接口,该接口用于向Bean容器种注册添加BeanDefinition。

为此,我们跟进FeignClientsRegistrar的registerBeanDefinitions方法,看看它注册了哪些东西。

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 注册默认配置
registerDefaultConfiguration(metadata, registry);
// 注册FeignClient接口的Bean
registerFeignClients(metadata, registry);
}

1、registerDefaultConfiguration方法将会读取@EnableFeignClients接口的属性,如果存在自定义配置类那么就会被注册到容器中。

2、registerFeignClients则会扫描所有注解了@FeignClient的接口,然后像spring本地Bean一样地注册到容器中。

扫描@FeignClient注解的接口

我们重点关注registerFeignClients方法,跟进代码

public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader); Set<String> basePackages; // 获取扫描路径 // 扫描所有路径,默认情况下扫描启动类下的路径
for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
// 遍历扫描到的FeignClient的Bean
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// verify annotated class is an interface
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName()); String name = getClientName(attributes);
// 注册FeignClient的配置
registerClientConfiguration(registry, name, attributes.get("configuration"));
// 注册FeignClient
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}

方法中的核心逻辑就是扫描类路径,获取BeanDefinition,然后遍历进行注册。

跟进registerFeignClient注册方法

private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
// 生成FeignClientFactoryBean这个BeanDefinition构造器
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class); // 将@FeignClient的注解属性添加到builder
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
String contextId = getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); String alias = contextId + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); // ... BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias });
// 注册
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}

这里值得注意的是genericBeanDefinition方法最终生成的其实是FeignClientFactoryBean,registerBeanDefinition方法注册进容器的也是FeignClientFactoryBean。

而FeignClientFactoryBean向上直接实现了FactoryBean接口

FactoryBean接口是spring开放出来的,用于自定义Bean的生成过程。也就是说,spring将会通过调用FeignClientFactoryBean的getObject来获取@FeignClient注解的接口对应的Bean对象。

总结

openfeign的自动配置过程逻辑相对比较简单,就是扫描了一下@FeignClient注解的接口,然后生成FeignClientFactoryBean的BeanDefinition给注册到容器当中。而具体的Bean对象,将会通过调用FeignClientFactoryBean的getObject方法来获取。

一、openfeign的自动配置的更多相关文章

  1. 企业IT管理员IE11升级指南【15】—— 代理自动配置脚本

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  2. 学记:为spring boot写一个自动配置

    spring boot遵循"约定优于配置"的原则,使用annotation对一些常规的配置项做默认配置,减少或不使用xml配置,让你的项目快速运行起来.spring boot的神奇 ...

  3. 网络连接详细信息出现两个自动配置ipv4地址

    问题:网络连接详细信息出现两个自动配置ipv4地址,一个是有效地址,一个是无效地址. 解决办法:先将本地连接ip设置成自动获取,然后点击开始——>运行——>输入cmd,回车,进入命令行界面 ...

  4. python环境变量自动配置脚本(setx使用)

    前言 setx不是windows系统自带的工具,需要到微软官网下载,但是有的系统也会自带.(是官方提供的,可放心食用) set和setx都可以用来配置环境变量.他们的不同点在于,set只是临时的修改环 ...

  5. 使用脚本自动配置matlab安装libsvm和随机森林工具箱

    前言 支持向量机(SVM)和随机森林 都是用于分类的机器学习算法. 这里我需要对网上的工具箱在matlab中进行配置. 效果演示: 1.双击运行“自动配置.bat” 2.matlab会自动启动,手动配 ...

  6. 转-IE浏览器自动配置代理脚本-Proxy.PAC文件及PAC相关语法

    用笔记本上网时,往返家里和单位,因为单位是用的代理上网,家里是直接连接.因此每次都要修改IE的代理设置,虽然是个小事,但是每次都要修改总是有点烦 ,于是参考GOOGLE,写了一个自动配置代理的脚本.这 ...

  7. Windows下Apache服务器中自动配置二级子域名

    今天我们介绍的这个办法,只需要简单修改 httpd-vhosts.conf 文件,配合 .htaccess 文件即可实现自动配置二级域名. 我们这里以 wpchina.com 为例,以下代码中的 wp ...

  8. [win]AD域组策略wifi自动配置

    http://wenku.baidu.com/link?url=MC950wliAZNeVUJ2M6Y1VTi5faqo7kG374fyBjW57r0qyLJkBZLg5ypiql4RFywQ8q7y ...

  9. spring boot实战(第十三篇)自动配置原理分析

    前言 spring Boot中引入了自动配置,让开发者利用起来更加的简便.快捷,本篇讲利用RabbitMQ的自动配置为例讲分析下Spring Boot中的自动配置原理. 在上一篇末尾讲述了Spring ...

随机推荐

  1. Flutter StatefulWidget 有状态组件、页面上绑定数据、改变页面数据

    在 Flutter 中自定义组件其实就是一个类,这个类需要继承 StatelessWidget/StatefulWidget. StatelessWidget 是无状态组件,状态不可变的 widget ...

  2. Python 相对导入attempted relative import beyond top-level package

    ValueError: attempted relative import beyond top-level package 假设有如下层次包目录 project/ __init__.py mypac ...

  3. hadoop记录-[Flink]Flink三种运行模式安装部署以及实现WordCount(转载)

    [Flink]Flink三种运行模式安装部署以及实现WordCount 前言 Flink三种运行方式:Local.Standalone.On Yarn.成功部署后分别用Scala和Java实现word ...

  4. Error:java: Compilation failed: internal java compiler

    errorInformation:java: javacTask: 源发行版 1.8 需要目标发行版 1.8 解决此类问题 检查自己的JDK是否一致 1  setting--------built  ...

  5. Django中的QuerySet查询优化之实例篇

    转载的,做个笔记,原文链接 在数据库有外键的时候,使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能.本文通过一个简单的例子 ...

  6. Spring Boot应用的打包和部署

    传统的Web应用在发布之前通常会打成WAR包,然后将WAR包部署到Tomcat等容器中使用,而通过前面的学习我们已经知道,Spring Boot应用既能以JAR包的形式部署,又能以WAR包的形式部署. ...

  7. delphi中我用定时器每隔一段时间执行操作

    delphi中,我用定时器每隔一段时间执行数据库插入及更新工作!adoquery.close;adoquery.sql.cleare;adoquery.connection:=con1;adoquer ...

  8. realloc(void *__ptr, size_t __size)

    #include <stdlib.h>realloc(void *__ptr, size_t __size):更改已经配置的内存空间,即更改由malloc()函数分配的内存空间的大小.如果 ...

  9. HTML布局水平导航条1制作

    该文是用css制作个导航条,用竖线分隔,导航条是点击的多个区块.步骤:ul里设置需要数量的li,li中加上a链接给ul加样式,去掉默认的前面的点给li设置左浮动,让ul里的li横向排列a链接设置成块状 ...

  10. C-LODOP回调多个返回值On_Return_Remain

    c-lodop默认一次只能回调一个值,回调后会销毁,如果想回调多个值,可加该语句:LODOP.On_Return_Remain=true;之前有博文:lodop和c-lodop通过打印状态和任务不在队 ...