1.Springboot之分布式事务框架Seata实现原理源码分析
2.SpringCloud原理OpenFeign之FeignClient动态代理生成原理
3.SpringBoot添加外部jar包及打包(亲测有效) - 第452篇
4.springcloud2022ï¼
5.Spring Cloud OpenFeign源码FeignClientFactoryBean原理
Springboot之分布式事务框架Seata实现原理源码分析
在SpringBoot环境下的码分分布式事务框架Seata实现原理涉及到了代理数据源、注册代理Bean以及全局事务拦截器等关键环节。码分下面我们将逐步解析其核心逻辑。码分
首先,码分Seata通过GlobalTransactionScanner来注册项目中所有带有@GlobalTransactional注解的码分方法类。该扫描器是码分Snapdragon Camera源码一个实现了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启动时,会调用该类的019朔源码燕窝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客户端动态代理所需的exe源码写成js各种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的远程调用功能。如果你对源码的深入理解感兴趣,下期文章将继续解析调用源码细节。