Feign底层原理剖析 (feign底层实现原理)

Feign底层原理剖析 (feign底层实现原理)

本文目录导航:

Feign底层原理剖析-智能装载&灵活代理

本篇文章仅引见Feign的智能装载与灵活代理机制等外容,不会过火深化细节。

1、什么是Feign?

这里套用Feign官网Github上的引见:“Feign是一个灵感来自于Retrofit、JAXRS-2.0、WebSocket的Java Http客户端,Feign的重要指标是降落大家经常使用Http API的复杂性”。

其实,Feign底层依赖于Java的灵活代理机制,对原生Java Socket或许Apache HttpClient启动封装,成功了基于Http协定的远程环节调用。

当然,Feign还在此基础上成功了负载平衡、熔断等机制。

2、为什么要经常使用Feign?

申明式Http Client相关于编程式Http Client代码逻辑愈加繁复,不须要处置复杂的编码恳求和照应,只须要像调用本地方法即可,提高编码效率

集中控制Http恳求方法,代码边界愈加明晰

更好的集成负载平衡、熔断升级等性能

3、Feign依赖注入原理

经常使用过Feign的同窗都知道,@EnableFeignClients注解是开启Fiegn性能的关键,咱们理论会在该注解中参与FeignClient的所在包,以便Spring容器能够扫描到一切的FeignClient,并启动托管。

前面咱们便可以经常使用@Autowired注解智能导入了。

@SpringBootApplication@EnableFeignClients(basePackages = {com.**})public class Application {}

该注解样式也是很多第三方包集成Springboot所经常使用的套路:普通都是开启该注解后,Springboot便可以智能装载第三方包所指定的Class,咱们便可以间接经常使用第三方包所提供的性能,十分繁难。

接上去不会详细引见智能装载的局部,而是间接给出智能装载的主头绪,看看Spring容器究竟装载了什么bean。

3.1、Feign智能装载

首先进入@EnableFeignClients源码中,检查该注解导入了什么Registrar注册器,这个注册器便是智能装载的关键。

@Retention()@Target()@Documented@Import()public @interface EnableFeignClients {...}

从源码中可以看出,@EnableFeignClients注解导入的是自定义的FeignClientsRegistrar类。

这种类型的注册器普通会承袭Spring中的ImportBeanDefinitionRegistrar接口,并在registerBeanDefinitions成功方法中向Spring容器注册一些bean,以到达智能注入第三方性能的目的。

// [1] 承袭ResourceLoaderAware和EnvironmentAwareclass FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {// [2] 注册自动的Feign性能registerDefaultConfiguration(metadata, registry);// [3] 注册一切定义的FeignClientregisterFeignClients(metadata, registry);}}

[1] 从类的定义中,咱们可以发现还成功了ResourceLoaderAware、EnvironmentAware两个Spring钩子接口,那么该注册类肯定持有资源加载器和Spring的环境变量等信息,这个不过多叙说。

[2] 该方法会从@EnableFeignClients注解中提取defaultConfiguration这个key和对应的value,并把它当作自动的Feign性能注册到Spring容器中。

假设没有该key,则不做任何处置。

[3] registerFeignClients方法会扫描@EnableFeignClients注解的basePackages,注册一切的FeignClient,上方详细引见。

public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();Map<String, Object> attrs = (());// [1] 失掉clients属性final Class<?>[] clients = attrs == null ? null : (Class<?>[]) (clients);if (clients == null || == 0) {// [2] 假设clients属性为null,则失掉basePackages属性,扫描其中的一切clientClassPathScanningCandidateComponentProvider scanner = getScanner();();(new AnnotationTypeFilter());Set<String> basePackages = getBasePackages(metadata);for (String basePackage : basePackages) {((basePackage));}} else {// [3] 假设clients属性不为null,则间接注入for (Class<?> clazz : clients) {(new AnnotatedGenericBeanDefinition(clazz));}}// [4] 遍历一切的clients,将其封装为BeanDefinition注册进Spring容器中for (BeanDefinition candidateComponent : candidateComponents) {if (candidateComponent instanceof AnnotatedBeanDefinition) {// verify annotated class is an interfaceAnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;AnnotationMetadata annotationMetadata = ();((), @FeignClient can only be specified on an interface);Map<String, Object> attributes = (());String name = getClientName(attributes);registerClientConfiguration(registry, name, (configuration));registerFeignClient(registry, annotationMetadata, attributes);}}}

registerFeignClients方法的代码稍微有点多,但重要思绪就是解析@EnableFeignClients注解,依据解析信息失掉FeignClients,而后包装成BeanDefinition注册进Spring容器中。详细分为以下几步:

[1] 首先解析@EnableFeignClients注解中的clients信息,假设存在,说明开发人员间接指定了FeignClient的全门路,因此只需加载这些全门路的class即可。

假设未指定,则经过扫包的形式加载。

[2] 假设clients属性为null,则创立一个扫描器Scanner,并指定要扫描的类肯定有FeignClient注解,而后经过getBasePackages()方法从@EnableFeignClients注解中失掉basePackages信息,最后遍历一切待扫描的包,将扫描到的FeignClient类参与candidateComponents中,待后续加载进容器。

[3] 假设clients属性不为null,上方也说了,会间接注入

[4] 到了这里,一切的FeignClient都被扫描到并且封装成BeanDefinition,接上去会遍历这些BeanDefinition,而后在()方法中判别这些BeanDefinition能否为接口,由于@FeignClient注解只能经常使用在接口上。

校验完后咱们应该关注registerFeignClient()这个真正注册FeignClient的方法。

private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,Map<String, Object> attributes) {String className = ();Class clazz = (className, null);ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory? (ConfigurableBeanFactory) registry : null;String contextId = getContextId(beanFactory, attributes);String name = getName(attributes);FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();(beanFactory);(name);(contextId);(clazz);BeanDefinitionBuilder definition = (clazz, () -> {(getUrl(beanFactory, attributes));(getPath(beanFactory, attributes));404((((decode404))));Object fallback = (fallback);if (fallback != null) {(fallback instanceof Class ? (Class<?>) fallback: ((), null));}Object fallbackFactory = (fallbackFactory);if (fallbackFactory != null) {(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory: ((), null));}return ();});(_BY_TYPE);(true);validate(attributes);AbstractBeanDefinition beanDefinition = ();(_TYPE_ATTRIBUTE, className);(feignClientsRegistrarFactoryBean, factoryBean);// has a default, wont be nullboolean primary = (Boolean) (primary);(primary);String[] qualifiers = getQualifiers(attributes);if ((qualifiers)) {qualifiers = new String[] { contextId + FeignClient };}BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);(holder, registry);}

registerFeignClient()是对单个FeignClient注册的方法。

这个方法乍一看很长,但其实主线十清楚晰。

就是将扫描到的BeanDefinition中的元信息提取进去,而后构形成一个Feign自定义的FactoryBean,即FeignClientFactoryBean,前面咱们每次失掉容器中的FeignClient时,就会经过该FactoryBean的getObject()方法中失掉(这个触及到了Spring容器中普通bean和FactoryBean的区别,大家可以自行去了解下)。

方法中的其它局部都是为上方所说的逻辑服务,包括FactoryBean的结构,BeanDefinition注入到容器中等环节。

咱们不用太过关心,只需抓住重点即可。

讲到这里,其实智能装载环节曾经成功了,容器中曾经蕴含了自定义的FeignClientFactoryBean。

这里用一张流程图总结下智能装载的全环节。

然而咱们临时还不知道智能装载的FeignClientFactoryBean究竟做了什么。

上方咱们就深化去了解。

3.2、FeignClientFactoryBean#getObject

FeignClientFactoryBean的源码如下:

public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {@Overridepublic Object getObject() {// [1] 真正的失掉对象的方法委托给getTarget()方法了return getTarget();}<T> T getTarget() {// 失掉Feign的高低文FeignContext context = beanFactory != null ? (): (); builder = feign(context);if (!(url)) {// [2] 假设url没有定义,则进入到该判别中创立对象,该判别中创立的对象具备负载平衡性能if (!(http)) {url = http:// + name;}else {url = name;}url += cleanPath();return (T) loadBalance(builder, context, new HardCodedTarget<>(type, name, url));}if ((url) && !(http)) {url = http:// + url;}// [3] 假设url定义了,说明用户指定了某台机器,也就没有必要启动负载平衡了,则从上方的方法创立对象String url = + cleanPath();// 可以发现上方的口头逻辑和loadBalance()十分像,只是多了两个if判别,这两个if判别就是移除负载平衡的关键Client client = getOptional(context, );if (client != null) {if (client instanceof FeignBlockingLoadBalancerClient) {// not load balancing because we have a url,// but Spring Cloud LoadBalancer is on the classpath, so unwrapclient = ((FeignBlockingLoadBalancerClient) client)();}if (client instanceof RetryableFeignBlockingLoadBalancerClient) {// not load balancing because we have a url,// but Spring Cloud LoadBalancer is on the classpath, so unwrapclient = ((RetryableFeignBlockingLoadBalancerClient) client)();}(client);}Targeter targeter = get(context, );return (T) (this, builder, context, new HardCodedTarget<>(type, name, url));}}// 创立负载平衡的clientprotected <T> T loadBalance( builder, FeignContext context, HardCodedTarget<T> target) {Client client = getOptional(context, );if (client != null) {(client);Targeter targeter = get(context, );return (this, builder, context, target);}throw new IllegalStateException(No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?);}

getObject()会依据用户定义的FeignClient能否认义url属性选择能否前往具备负载平衡属性的对象。详细环节如下:

[1] 重写的方法委托给getTarget()口头了

[2] 假设没有定义url,则间接经过loadBalance()方法创立代理对象。

此时会先冷静器中拿到Client对象,而后经常使用()方法创立Client的代理对象。

留意,咱们最终经常使用的FeignClient是Client的灵活代理对象,而Client对象是真正口头http恳求的对象。

Client普通是httpClient或许是Feign自定义的具备LoadBalance性能的LoadBalancerClient。

前者很好了解,可以间接以为是Apache HttpClient;后者是Feign在Apache HttpClient的基础上封装了Spring Cloud Loadbalancer一系列对象,而Apache HttpClient作为被封装的delegate,在delegate真正口头http恳求时同时启动Loadbalancer的负载平衡逻辑。

[3] 假设url曾经定义了,说明用户指定了详细某台机器,此时曾经没有必要启动负载平衡了(

如何评估华为新开源的servicecomb微服务框架?

ServiceComb,华为开源的微服务框架,源自外部CSE框架,撑持了多个大型名目,成为华为一致微服务规范。

只管刚开源,版本为0.X,但已宽泛运行。

其设计器重通讯性能,经过外部应战和测试,确保REST和highway性能。

启动时期争议,倡导反应社区剖析要素,华为外部体验理论更快。

关于言语支持,Go局部行将开源,C局部暂未方案开源,而Service Mesh已上线华为私有云,无偿经常使用。

ServiceComb不依赖zuul做gateway,外部成功Edge Service框架,性能优化清楚。

提供相似Fegin、SpringMVC、JAXRS的开发形式,集成Netflix OSS组件,简化运行构建。

ServiceComb与SpringBoot兼容,提供SpringBoot封装,繁难运行构建,但也不限度SpringCloud或其余框架的经常使用。

与Dubbo相比,以为其实用于SOA时代,但在微服务中存在局限。

关于框架经常使用,倡导依据运行需求选用,防止全盘控制,同时应用封装好的框架以简化开发环节。

评估ServiceComb,团队专一满足用户需求,谋求框架易用性和稳固性。

代码自持,不谋求外表赞誉,不漠视外在价值。

作为微服务框架,ServiceComb旨在提供高效、稳固和片面的微服务处置方案,顺应不同运行需求,促成微服务生态的开展。

300道SpringCloud面试题及答案(最新整顿)

最新SpringCloud面试题及答案【附答案解析】以下是SpringCloud面试题及答案,蕴含SpringCloud最新面试题及新答案。

这些答案包括了自己总结的局部和网上收集整顿的内容。

虽或许存在一些失误,但可作为参考。

如有发现失误,欢迎斧正,感谢。

假设不背 SpringCloud面试题的答案,面试或许会遇到艰巨。

这套SpringCloud面试题大全,宿愿能为你的预备提供协助。

此外,还有一份7000多页的Java面试题PDF大全,也请一并参考。

以下为SpringCloud外围组件及其作用和上班原了解析:1. Eureka:服务控制组件,担任服务注册中心与客户端服务发现机制。

2. Ribbon:负载平衡服务调用组件,提供多种负载平衡战略。

3. Hystrix:服务容错组件,驳回断路器形式,为依赖服务的出错和提前提供容错才干。

4. Feign:基于Ribbon和Hystrix的申明式服务调用组件。

5. Zuul:API网关组件,提供恳求路由与过滤性能。

Netflix OSS开源组件集成,包括Eureka、Hystrix、Ribbon、Feign、Zuul等外围组件。

这些组件在微服务架构中表演着关键角色。

负载平衡的意义在于改善计算资源的上班负载散布,优化资源经常使用,提高最大吞吐量,缩短照应时期,并防止繁多资源过载。

经过多个组件启动负载平衡,可以提高系统的牢靠性和可用性。

Feign是一个申明性Web服务客户端,简化了Web服务客户端的成功,用户只需定义形象方法并参与注解,无需构建HTTP恳求,间接调用接口即可。

Eureka与ZooKeeper在服务注册与发现上有所不同:Eureka驳回AP战略,自我包全机制防止服务注册列表过时服务被移除;ZooKeeper驳回CP战略,但在选举时期注册服务或许瘫痪。

Eureka的高可用性设计经过网络分区疑问处置。

微服务的特点包括:服务颗粒度小、可独立开发与部署、驳回松耦合设计、有形态化服务,支持独立裁减、更新与交流。

微服务限流理论经过IP限流、时期窗口限流等形式成功,以防止服务过载。

Spring Cloud Netflix提供了一系列用于集成Netflix OSS组件的工具,包括Eureka、Hystrix、Ribbon、Feign、Zuul等。

端到端微服务测实验证了上班流的完整性,确保系统作为一个全体协同上班。

Netflix Feign是基于Retrofit、JAXRS-2.0和WebSocket的Java客户端联编程序,简化了HTTP API的调用。

OAuth协定准许经过HTTP服务启用客户端运行程序访问资源一切者的资源,成功资源共享。

Ribbon是Netflix颁布的一个开源名目,提供客户端软件负载平衡算法,支持负载平衡战略。

Spring Cloud放弃了Dubbo的RPC通讯,驳回基于HTTP的REST形式,提供了更灵敏的服务调用。

Idempotence个性确保在远程服务或数据源中处置指令屡次时,结果坚持不变。

SpringBoot支持Jetty、Tomcat和Undertow等嵌入式容器,提供了方便的部署形式。

客户端证书用于远程主机收回经过身份验证的恳求,提供身份验证保障。

REST与RPC对比,REST是轻量级接口,服务提供与调用不存在代码耦合,依赖商定;RPC服务提供方与调用方存在强依赖,须要接口定义和版本控制。

散布式性能中心用于灵活变卦名目性能信息,无需从新部署名目。

链路跟踪Sleuth经过参与追踪信息辅佐监控系统调用链路。

服务注册与发现机制经过Eureka等服务提供支持,简化服务查找与控制。

WebMvcTest注释用于在Spring MVC运行程序中启动单元测试,专一于测试Spring MVC组件。

双要素身份验证为登录环节参与第二层验证,提供更强的安保性。

不同类型的微服务测试包括底层技术测试、两边层探求性测试和顶层验收测试。

Eureka作为SpringCloud的服务注册性能主机,是服务注册中心,经过客户端衔接并监控微服务形态。

罕用网关框架包括Nginx、Zuul和Gateway等。

Hystrix用于隔离远程系统访问点,成功服务容错与弹性。

微服务容器控制有助于独自部署和开发基于微服务的运行程序。

SpringCloud与Dubbo的区别在于性能、架构、保养难度和实用场景。

SpringCloud Config支持实时刷新性能。

Zookeeper经过复制机制确保CP个性。

微服务之间可经过同步通讯(RPC、REST)或异步通讯(信息队列)启动独立通讯。

OAuth协定准许第三方运行程序访问资源一切者的资源。

Eureka服务注册与发现原理包括活期心跳检测、复制服务虚例信息和客户端缓存。

Zuul与Nginx的区别在于成功言语、性能和自定义操作。

Spring Cloud是一个集成外部系统集成的矫捷框架,提供版本化/散布式性能、服务注册与发现、服务调用、路由、断路器与负载平衡、散布式信息传递等性能。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

25阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读