皮皮网
皮皮网

【手赚 平台 源码】【终极优化源码】【急速版源码】springfeign源码分析

来源:web api jwt源码 发表时间:2024-12-22 15:00:21

1.Springboot之分布式事务框架Seata实现原理源码分析
2.SpringCloud原理OpenFeign之FeignClient动态代理生成原理
3.SpringBoot添加外部jar包及打包(亲测有效) - 第452篇
4.springcloud2022?
5.Spring Cloud OpenFeign源码FeignClientFactoryBean原理

springfeign源码分析

Springboot之分布式事务框架Seata实现原理源码分析

       在SpringBoot环境下的码分分布式事务框架Seata实现原理涉及到了代理数据源、注册代理Bean以及全局事务拦截器等关键环节。码分下面我们将逐步解析其核心逻辑。码分

       首先,码分Seata通过GlobalTransactionScanner来注册项目中所有带有@GlobalTransactional注解的码分方法类。该扫描器是码分手赚 平台 源码一个实现了BeanPostProcessor接口的类,它能够在Spring容器初始化时进行后置处理,码分从而实现全局事务的码分管理。

       GlobalTransactionScanner实际上是码分一个InstantiationAwareBeanPostProcessor,它在实例化Bean前执行postProcessBeforeInstantiation方法,码分在实例化后执行postProcessAfterInstantiation方法,码分并在属性填充时执行postProcessProperties方法。码分尽管GlobalTransactionScanner类本身并未覆盖这3个方法,码分但在父类的码分实现中,这些方法用于处理Bean的码分实例化和属性设置过程。

       关键在于postProcessAfterInitialization方法中实现的wrapIfNecessary方法,该方法在GlobalTransactionScanner类中被重写。当方法执行到existsAnnotation方法判断类方法是否带有@GlobalTransactional注解时,如果存在则创建一个GlobalTransactionalInterceptor作为拦截器处理全局事务。

       在创建代理数据源时,Seata通过DataSourceProxy对系统默认数据源进行代理处理。通过shouldSkip方法判断当前bean是否需要被代理,如果bean是SeataProxy的子类且不是DataSource的子类且不在excludes集合中,则进行代理,从而代理当前系统的默认数据源对象。

       全局事务拦截器主要负责全局事务的发起、执行和回滚。终极优化源码在执行全局事务的方法被代理时,具体的执行拦截器是GlobalTransactionalInterceptor。该拦截器处理全局事务的逻辑,包括获取全局事务、开始全局事务、执行本地业务、提交本地事务、记录undo log、提交数据更新等步骤。其中,提交本地事务时会向TC(Transaction Coordinator)注册分支并提交本地事务,整个过程确保了分布式事务的一致性。

       当全局事务中任何一个分支发生异常时,事务将被回滚。参与全局事务的组件在异常发生时执行特定的回滚逻辑,确保事务一致性。在Seata的实现中,异常处理机制确保了事务的回滚能够正确执行。

       Seata还提供了XID(Transaction Identifier)的传递机制,通过RestTemplate和Feign客户端进行服务间的调用,确保分布式系统中各个服务能够共享和处理全局事务。RestTemplate在请求头中放置TX_XID头信息,而Feign客户端通过从调用链中获取Feign.Builder,最终通过SeataHystrixFeignBuilder.builder方法实现XID的传递。

       在被调用端(通过Feign调用服务),Seata自动配置会创建数据源代理,急速版源码使得事务方法执行时能够获取到连接对象,而这些连接对象已经被代理成DataSourceProxy。SeataHandlerInterceptor拦截器对所有请求进行拦截,从Header中获取TX_XID,参与者的XID绑定到上下文中,通过ConnectionProxy获取代理连接对象。在数据库操作中,XID绑定到ConnectionContext,执行SQL语句时通过StatementProxy或PreparedStatementProxy代理连接,从而完成全局事务的处理。

       综上所述,Seata通过一系列复杂的逻辑和机制,实现了SpringBoot环境下的分布式事务管理,确保了分布式系统中数据的一致性和可靠性。

SpringCloud原理OpenFeign之FeignClient动态代理生成原理

       在SpringCloud框架中,OpenFeign组件提供了基于Java接口的HTTP客户端实现。本文将深入剖析OpenFeign中的FeignClient动态代理生成原理,从@EnableFeignClinets注解的作用、Feign客户端接口动态代理的生成源码剖析以及Feign动态代理构造过程总结三方面进行详细阐述。

       首先,我们来分析@EnableFeignClinets注解的作用。这个注解实际上是整个Feign组件的入口,通过@Import注解导入FeignClientsRegistrar类,该类实现了ImportBeanDefinitionRegistrar接口,当Spring Boot启动时,会调用该类的游戏源码学习registerBeanDefinitions方法动态注入bean到Spring容器中。其中,registerFeignClients方法负责扫描带有@FeignClient注解的类,并生成对应的BeanDefinition。

       在Feign客户端接口动态代理的生成源码剖析部分,我们主要关注FeignAutoConfiguration和FeignClientsConfiguration配置类。FeignAutoConfiguration是Feign在整个SpringCloud中的配置类,其中会注入一系列FeignClientSpecification对象,并将其封装到FeignContext中,最后将FeignContext注入到Spring容器中。FeignContext是进行配置隔离的关键组件,它内部维护了每个客户端对应的AnnotationConfigApplicationContext、配置类的封装以及父容器等信息。通过这种方法,每个客户端的配置能够在独立的ApplicationContext中进行解析,实现了配置的隔离。

       接着,我们深入解析NamedContextFactory的作用,它用于进行配置隔离,确保Ribbon和Feign的配置能够被独立管理。通过构建独立的ApplicationContext,每个客户端的配置能够在自己的上下文中进行解析,避免了配置冲突。此外,我们还会剖析FeignClientsConfiguration,这是一个默认配置类,其中包含了生成Feign客户端动态代理所需的奔驰外挂源码各种bean,如解析SpringMVC注解的能力、构建动态代理的类等。

       在构建动态代理的过程中,整个流程涉及多个关键步骤:扫描并生成BeanDefinition、注入FeignClientFactoryBean、获取代理对象等。具体而言,当@EnableFeignClinets注解生效时,会扫描所有带有@FeignClient注解的接口并生成对应的BeanDefinition。随后,通过FeignClientFactoryBean重新生成一个bean定义,注册到Spring容器中。当需要获取代理对象时,通过FeignClientFactoryBean的getObject方法调用getTarget(),进一步获取到代理对象。整个过程涉及Feign.Builder的配置、组件的获取以及最终通过Feign.Builder构建动态代理对象。

       综上所述,OpenFeign在SpringCloud框架中的实现,通过一系列的注解、配置类以及组件的协作,实现了基于Java接口的HTTP客户端的动态代理生成。从@EnableFeignClinets的注解作用到Feign客户端接口的动态代理生成,再到Feign动态代理的构造过程,整个流程设计精巧,有效提高了服务间的互操作性和可维护性。对于希望深入理解OpenFeign原理的开发者而言,本文提供的分析和总结将有助于更好地掌握这一技术。

       最后,尽管本文已经详细阐述了OpenFeign的动态代理生成原理,但对于Feign与Ribbon的整合以及其他SpringCloud组件的原理,未来将会有更多深入分析的文章。通过本文的总结,希望能为读者提供一个清晰的视角,以便在实际项目中灵活运用OpenFeign实现高效、稳定的远程调用。

SpringBoot添加外部jar包及打包(亲测有效) - 第篇

       历史文章(文章累计+)《 国内最全的Spring Boot系列之一》《 国内最全的Spring Boot系列之二》《 国内最全的Spring Boot系列之三》《 国内最全的Spring Boot系列之四》《 国内最全的Spring Boot系列之五》深入Feign源码吃透Spring扩展点「扩展点实战系列」- 第篇

       利用Spring扩展点对敏感信息加密解密,一文集齐n多知识点「扩展点实战系列」」- 第篇 利用Spring扩展点模拟MyBatis的注解编程「知识点多多」「扩展点实战系列」- 第篇 走进MyBatis源码一探Spring扩展点「知识点多多」「扩展点实战系列」- 第篇 走进SpringBoot源码吃透Spring扩展点「扩展点实战系列」- 第篇 5个月的精华:Spring/SpringBoot扩展点手册:手册在手,编码无忧:全网独一份 - 第篇

       悟纤:师傅,最近使用spring-boot-maven-plugin导出jar包之后,运行不起来,报ClassNotFoundException。

       师傅:那ClassNotFoundException指向的类是Spring Boot starter的类,还是项目中的类,还是?

       悟纤:这个类是项目中引入的外部jar包中的类。

       师傅:那这样子的话,很有可能就是在打包的时候,外部jar包没有一起被打包进来了,这要解决了这个问题,那么问题就迎刃而解了。

       师傅:有些时候,问题并不是很难,我们要学习的就是学习分析问题,然后解决问题,这也是拉开和别人的差距。

       悟纤:那师傅我自己去好好研究下~

       师傅:去吧,学会分析问题,解决问题,超越自己。

       导读

       最近在研究web3的时候,有些依赖包,并没有在maven仓库中,需要从git上下载源码,然后编译打包,最后在引入到项目中。

       引入使用之后,编译以及在开发工具运行都是很正常的,但打完包之后,一运行就报错了,通常报错是Caused by: java.lang.ClassNotFoundException,所以这一节就来解决一下两个问题:

       (1)如何添加外部jar包?

       (2)如何打包外部jar包?

       题外话:最近把Spring/Spring扩展点实战系列写完之后,就不知道要写哪方面的文章了,大家对什么感兴趣,可以留言~

       一、添加外部jar包

       准备一个外部jar包,比如api.jar:

       在项目路径下创建一个文件夹libs,将api.jar放到libs下。

       添加外部jar依赖:

       添加完之后,代码中就可以使用到该jar里的类和方法。

       说明:

       (1)groupI、artifactId、version随便填写,并不一定要和api.jar的信息,但肯定是要一定的规范和关联性会比较好了。

       (2)scope=system表示此依赖是来自外部jar,而不是maven仓库。当scope设置为system时,systemPath属性才会生效,systemPath为一个物理文件路径,来指定依赖的jar其物理磁盘的位置。

       (3)${ project.basedir}代表根目录。

       二、打包外部jar包

       上面哪一步仅仅是引用到了项目里,打包的时候是不会打包到jar/war中的。对于Spring Boot的项目,一般都会使用到打包插件,那么只需要添加一个配置即可,如下:

       说明:重要的是includeSystemScope为true。

       如果有些配置文件,并非Spring Boot的默认路径,那么可能就需要借助resouce配置(resources节点和plugins节点同级):

       总结

       (1)如何添加外部jar包:指定score=system,并且配置sysemPath。

       (2)如何打包外部jar包:使用spring-boot-maven-plugin,并且配置属性includeSystemScope为true。

       最近把Spring/Spring扩展点实战系列写完之后,就不知道要写哪方面的文章了,大家对什么感兴趣,可以留言~

springcloud?

       å¾®æœåŠ¡æ¡†æž¶ä¹‹SpringCloud简介

       åœ¨äº†è§£SpringCloud之前先了解一下微服务架构需要考量的核心关键点,如下图:

       å¯¹äºŽä»¥ä¸Šç­‰æ ¸å¿ƒå…³é”®ç‚¹çš„处理,不需要我们重复造车轮,SpringCloud已经帮我们集成了,它使用SpringBoot风格将一些比较成熟的微服务框架组合起来,屏蔽掉了复杂的配置和实现原理,为快速构建微服务架构的应用提供了一套基础设施工具和开发支持。

       SpringCloud所提供的核心功能包含:

       SpringCloud架构图

       SpringCloud子项目

       SpringCloud旗下的子项目大致可以分为两类:

       å¦‚下:

       1.SpringCloud与SpringBoot

       SpringBoot可以说是微服务架构的核心技术之一。通过在SpringBoot应用中添加SpringMVC依赖,就可以快速实现基于REST架构的服务接口,并且可以提供对HTTP标准动作的支持。而且SpringBoot默认提供JackJson序列化支持,可以让服务接口输入、输出支持JSON等。因此,当使用SpringCloud进行微服务架构开发时,使用SpringBoot是一条必经之路。

       2.SpringCloud与服务治理(Eureka)

       æœåŠ¡æ²»ç†æ˜¯SpringCloud的核心,在实现上其提供了两个选择,即Consul和Netflix的Eureka。

       Eureka提供了服务注册中心、服务发现客户端,以及注册服务的UI界面应用。

       åœ¨Eureka的实现中,节点之间相互平等,有部分注册中心“挂掉”也不会对整个应用造成影响,即使集群只剩一个节点存活,也可以正常地治理服务。即使所有服务注册节点都宕机,Eureka客户端中所缓存的服务实例列表信息,也可让服务消费者能够正常工作,从而保障微服务之间互相调用的健壮性和应用的弹性。

       3.SpringCloud与客户端负载均衡(Ribbon)

       Ribbon默认与Eureak进行无缝整合,当客户端启动的时候,从Eureka服务器中获取一份服务注册列表并维护在本地,当服务消费者需要调用服务时,Ribbon就会根据负载均衡策略选择一个合适的服务提供者实例并进行访问。

       SpringCloud通过集成Netflix的Feign项目,为开发者提供了声明式服务调用,从而简化了微服务之间的调用处理方式。并且默认Feign项目集成了Ribbon,使得声明式调用也支持客户端负载均衡功能。

       4.SpringCloud与微服务容错、降级(Hystrix)

       ä¸ºäº†ç»™å¾®æœåŠ¡æž¶æž„提供更大的弹性,在SpringCloud中,通过集成Netflix下子项目Hystrix,通过所提供的@HystrixCommand注解可以轻松为我们所开发的微服务提供容错、回退、降级等功能。此外,Hystrix也默认集成到Feign子项目中。

       Hystrix是根据“断路器”模式而创建。当Hystrix监控到某服务单元发生故障之后,就会进入服务熔断处理,并向调用方返回一个符合预期的服务降级处理(fallback),而不是长时间的等待或者抛出调用异常,从而保障服务调用方的线程不会被长时间、不必要地占用,避免故障在应用中的蔓延造成的雪崩效应。

       è€ŒHystrix的仪表盘项目(Dashboard)可以监控各个服务调用所消耗的时间、请求数、成功率等,通过这种近乎实时的监控和告警,可以及时发现系统中潜在问题并进行处理。

       5.SpringCloud与服务网关(Zuul)

       SpringCloud通过集成Netflix中的Zuul实现API服务网关功能,提供对请求的路由和过滤两个功能

       è·¯ç”±åŠŸèƒ½è´Ÿè´£å°†å¤–部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。

       è¿‡æ»¤å™¨åŠŸèƒ½åˆ™è´Ÿè´£å¯¹è¯·æ±‚的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。

       é€šè¿‡Zuul,可以将细粒度的服务组合起来提供一个粗粒度的服务,所有请求都导入一个统一的入口,对外整个服务只需要暴露一个API接口,屏蔽了服务端的实现细节。通过Zuul的反向代理功能,可以实现路由寻址,将请求转发到后端的粗粒度服务上,并做一些通用的逻辑处理。此外,Zuul默认会与Eureka服务器进行整合,自动从Eureka服务器中获取所有注册的服务并进行路由映射,实现API服务网关自动配置。

       6.SpringCloud与消息中间件(Stream)

       SpringCloud为简化基于消息的开发,提供了Stream子项目,通过建立消息应用抽象层,构建了消息收发、分组消费和消息分片等功能处理,将业务应用中的消息收发与具体消息中间件进行解耦,使微服务应用开发中可以非常方便地与Kafka和RabbitMQ等消息中间件进行集成。

       SpringCloudBus基于Stream进行扩展,可以作为微服务之间的事件、消息总线,用于服务集群中状态变化的传播。

       æ¯”如SpringCloudConfig借助Bus,可以实现配置的动态刷新处理。

       7.SpringCloud与分布式配置中心(Config)

       é’ˆå¯¹å¾®æœåŠ¡æž¶æž„下的配置文件管理需求,SpringCloud提供了一个Config子项目。SpringCloudConfig具有中心化、版本控制、支持动态更新和语言独立等特性。

       åœ¨Config子项目中将微服务应用分为两种角色:配置服务器(ConfigServer)和配置客户端(ConfigClient)。使用配置服务器集中地管理所有配置属性文件,配置服务中心可以将配置属性文件存储到Git、SVN等具有版本管理仓库中,也可以存放在文件系统中。默认采用Git的方式进行存储,因此可以很容易地对配置文件进行修改,并实现版本控制。

       8.SpringCloud与微服务链路追踪(Sleuth)

       SpringCloud中的Sleuth子项目为开发者提供了微服务之间调用的链路追踪。

       Sleuth核心思想就是通过一个全局的ID将分布在各微服务服务节点上的请求处理串联起来,还原了调用关系,并借助数据埋点,实现对微服务调用链路上的性能数据的采集。

       å› æ­¤ï¼Œé€šè¿‡Sleuth可以很清楚地了解到一个用户请求经过了哪些服务、每个服务处理花费了多长时间,从而可以对用户的请求进行分析。此外,通过将采集的数据发送给Zipkin进行存储、统计和分析,从而可以实现可视化的分析和展示,帮助开发者对微服务实施优化处理。

       9.SpringCloud与微服务安全(Security)

       SpringCloudSecurity为我们提供了一个认证和鉴权的安全框架,实现了资源授权、令牌管理等功能,同时结合Zuul可以将认证信息在微服务调用过程中直接传递,简化了我们进行安全管控的开发。

       SpringCloudSecurity默认支持OAuth2.0认证协议,因此单点登录也可以非常容易实现,并且OAuth2.0所生成的令牌可以使用JWT的方式,进一步简化了微服务中的安全管理。

       .SpringCloud的其他子项目

       è‡ªå®šä¹‰springcloud-gateway熔断处理

       ä¸€ã€åœºæ™¯

       ä½¿ç”¨springcloudgateway后,有了熔断,问题也就随之而来,服务间调用有了hystrix可以及时的排除坏接口、坏服务的问题,对系统很有帮助。但是!不是所有的接口都是极短时间内完成的,不是所有的接口都可以设置一样的超时时间的!

       é‚£ä¹ˆæˆ‘们面临一个问题,那就是百分之的接口都可以在1s内完美完成,但是就是那几个特殊接口,需要十几秒,几十秒的等待时间,而默认熔断的时间又只有一个。

       äºŒã€åˆ†æž

       åœ¨å‰é¢springcloudgateway源码解析之请求篇中我们知道请求会经过一些列的过滤器(GatewayFilter),而springcloudgateway的降级熔断处理就是由一个特殊的过滤器来处理的,通过源码分析我们关注到HystrixGatewayFilterFactory这个类,这个类的作用就是生产GatewayFilter用的,我们看下它的实现

       å¯ä»¥çœ‹åˆ°çº¢æ¡†å¤„最后构建了一个匿名的GatewayFilter对象返回,这个对象在接口请求过程中会被加载到过滤器链条中,仔细看到这里是创建了一个RouteHystrixCommand这个命令对象,最终调用command.toObservable()方法处理请求,如果超时熔断调用resumeWithFallback方法

       é€šè¿‡æºç åˆ†æžgateway在路由时可以指定HystrixCommandKey,并且对HystrixCommandKey设置超时时间

       ä¸‰ã€æ–¹æ¡ˆ

       çŸ¥é“网关熔断的原理就好办了,自定义熔断的过滤器配置到接口请求过程中,由过滤器来读取接口熔断配置并构建HystrixObservableCommand处理请求。

       è‡ªå®šä¹‰ä¸€ä¸ªç±»XXXGatewayFilterFactory继承AbstractGatewayFilterFactory,将api和对应的timeout配置化,来实现细化到具体接口的熔断配置,具体实现如下:

       packageorg.unicorn.framework.gateway.filter;

       importcn.hutool.core.collection.CollectionUtil;

       importcom.netflix.hystrix.HystrixCommandGroupKey;

       importcom.netflix.hystrix.HystrixCommandKey;

       importcom.netflix.hystrix.HystrixCommandProperties;

       importcom.netflix.hystrix.HystrixObservableCommand;

       importcom.netflix.hystrix.exception.HystrixRuntimeException;

       importorg.springframework.beans.factory.ObjectProvider;

       importorg.springframework.cloud.gateway.filter.GatewayFilter;

       importorg.springframework.cloud.gateway.filter.GatewayFilterChain;

       importorg.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;

       importorg.springframework.cloud.gateway.support.ServerWebExchangeUtils;

       importorg.springframework.cloud.gateway.support.TimeoutException;

       importorg.springframework.core.annotation.AnnotatedElementUtils;

       importorg.springframework.mand;

       if(CollectionUtil.isNotEmpty(apiTimeoutList)){

       //request匹配属于那种模式

ApiHystrixTimeoutapiHystrixTimeout=getApiHystrixTimeout(apiTimeoutList,path);

command=newUnicornRouteHystrixCommand(config.getFallbackUri(),exchange,chain,initSetter(apiHystrixTimeout.getApiPattern(),apiHystrixTimeout.getTimeout()));

       }else{

       command=newUnicornRouteHystrixCommand(config.getFallbackUri(),exchange,chain,initSetter(serviceId(exchange),null));

       }

       returncommand;

}

       /

***@paramapiTimeoutList

*@parampath

*@return

*/

privateApiHystrixTimeoutgetApiHystrixTimeout(ListapiTimeoutList,Stringpath){

       for(ApiHystrixTimeoutapiTimeoutPattern:apiTimeoutList){

       if(this.antPathMatcher.match(apiTimeoutPattern.getApiPattern(),path)){

       returnapiTimeoutPattern;

}

       }

       ApiHystrixTimeoutapiHystrixTimeout=newApiHystrixTimeout();

       apiHystrixTimeout.setApiPattern("default");

       apiHystrixTimeout.timeout=null;

       returnapiHystrixTimeout;

}

       @Override

publicGatewayFilterapply(Configconfig){

       return(exchange,chain)-{

       UnicornRouteHystrixCommandcommand=initUnicornRouteHystrixCommand(exchange,chain,config);

returnMono.create(s-{

       Subscriptionsub=command.toObservable().subscribe(s::success,s::error,s::success);

       s.onCancel(sub::unsubscribe);

}).onErrorResume((Function)throwable-{

       if(throwableinstanceofHystrixRuntimeException){

       HystrixRuntimeExceptione=(HystrixRuntimeException)throwable;

HystrixRuntimeException.FailureTypefailureType=e.getFailureType();

switch(failureType){

       caseTIMEOUT:

       returnMono.error(newTimeoutException());

       caseCOMMAND_EXCEPTION:{

       Throwablecause=e.getCause();

if(causeinstanceofResponseStatusException||AnnotatedElementUtils

       .findMergedAnnotation(cause.getClass(),ResponseStatus.class)!=null){

       returnMono.error(cause);

}

       }

       default:

       break;

}

       }

Spring Cloud OpenFeign源码FeignClientFactoryBean原理

       Spring Cloud OpenFeign的FeignClientFactoryBean在实例化过程中,通过FactoryBean接口实现,GetObject方法的关键步骤包括获取FeignContext、配置Feign.Builder、创建HardCodedTarget和调用loadBalance方法。这些步骤涉及自动配置、FeignClientSpecification的使用、Logger和Builder组件的定制以及动态代理的生成。最后,getObject方法返回的是一个接口的代理类,用于执行远程调用。

       详细分析:

       FeignClientFactoryBean在Spring容器中,通过getObject方法转化为实际的FeignClient实例。首先,它从FeignContext获取相关配置,这个配置在引入OpenFeign依赖时自动注入。接下来,通过getTarget方法,FeignClientFactoryBean配置了Builder组件,如Logger(非Slf4j)、RequestInterceptor、Encoder和Decoder等,同时考虑了用户自定义组件的配置。之后,创建了HardCodedTarget,基于FeignClient接口、注解值和完整URL构建,然后通过loadBalance方法,整合了LoadBalancerFeignClient和HystrixTargeter,进行负载均衡和目标URL定位。

       在newInstance方法中,解析了接口方法的注解,生成了MethodHandler,并用FeignInvocationHandler封装,这个InvocationHandler在代理类实例化时被调用,实现了远程调用。最终,通过Proxy.newProxyInstance动态生成了代理类,完成FeignClientFactoryBean的实例化过程。

       总的来说,FeignClientFactoryBean实例化是通过一系列配置和代理生成,实现了Spring Cloud OpenFeign的远程调用功能。如果你对源码的深入理解感兴趣,下期文章将继续解析调用源码细节。

相关栏目:探索