源码分析SpringCloud Gateway如何加载断言(predicates)与过滤器(filters)

  我们今天的主角是Gateway网关,一听名字就知道它基本的任务就是去分发路由。根据不同的指定名称去请求各个服务,下面是Gateway官方的解释:

Spring Cloud Gateway,其他的博主就不多说了,大家多去官网看看,只有官方的才是最正确的,回归主题,我们的过滤器与断言如何加载进来的,并且是如何进行对请求进行过滤的。

  大家如果对SpringBoot自动加载的熟悉的话,一定知道要看一个代码的源码,要找到META-INF下的spring.factories,具体为啥的博主就不多说了,网上也有很多讲解自动加载的源码分析,今天就讲解Gateway,所有项目三板斧:加依赖、写注解、弄配置

  依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>

  注解:启动类上需要添加@EnableDiscoveryClient,启动服务发现

  配置:

spring:cloud:gateway:routes:- id: after-route #id必须要唯一uri: lb://product-centerpredicates:- After=2030-12-16T15:53:22.999+08:00[Asia/Shanghai]filters:- PrefixPath=/product-api    

  大家看到这个配置的时候,为什么我们写After断言与PrefixPath过滤器,gateway就会自动识别呢,那我们有没有那一个地方可以看到所有的自带的属性呢?当然有,而且我们本篇就主要讲解为什么gateway会自动识别,并且我们要自己实现并且添加自定义属性。开始源码解析第一步,找到自动加载的类一探究竟;

   看到这里的时候,第一步就成功了,剩下的就是找到org.springframework.cloud.gateway.config.GatewayAutoConfiguration这个关键类,我们主要看看里面的两个类

    @Beanpublic RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,List<GatewayFilterFactory> GatewayFilters,List<RoutePredicateFactory> predicates,RouteDefinitionLocator routeDefinitionLocator) {return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties);}@Bean@Primary//TODO: property to disable composite?public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));}

  这俩个类配置,大家可能非常熟悉,大家上手一个新知识点的时候,肯定会找一些快速入门的文章看看,博主还是习惯直接找官方的quick start来看,大家可以看看这些快速上手项目:Getting Started | Building a Gateway

  所以博主直接就找到了RouteLocator这个类配置,果不其然,我们找到了断言与过滤器的注入,虽然实在方法体内作为参数传入,但是会被spring解析到,直接去工厂里拿到,具体怎么拿呢?我们再来看看:

 1 public BeanWrapper instantiateUsingFactoryMethod(2             String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {3 4         .....5 6             for (Method candidate : candidates) {7                 Class<?>[] paramTypes = candidate.getParameterTypes();8 9                 if (paramTypes.length >= minNrOfArgs) {
10                     ArgumentsHolder argsHolder;
11 
12                     if (explicitArgs != null) {
13                         // Explicit arguments given -> arguments length must match exactly.
14                         if (paramTypes.length != explicitArgs.length) {
15                             continue;
16                         }
17                         argsHolder = new ArgumentsHolder(explicitArgs);
18                     }
19                     else {
20                         // Resolved constructor arguments: type conversion and/or autowiring necessary.
21                         try {
22                             String[] paramNames = null;
23                             ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
24                             if (pnd != null) {
25                                 paramNames = pnd.getParameterNames(candidate);
26                             }
27                             //主要就是会进入到这里去解析每一个参数类型
28                             argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
29                                     paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
30                         }
31                         catch (UnsatisfiedDependencyException ex) {
32                             if (logger.isTraceEnabled()) {
33                                 logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
34                             }
35                             // Swallow and try next overloaded factory method.
36                             if (causes == null) {
37                                 causes = new LinkedList<>();
38                             }
39                             causes.add(ex);
40                             continue;
41                         }
42                     }
43 
44                     int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
45                             argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
46                     // Choose this factory method if it represents the closest match.
47                     if (typeDiffWeight < minTypeDiffWeight) {
48                         factoryMethodToUse = candidate;
49                         argsHolderToUse = argsHolder;
50                         argsToUse = argsHolder.arguments;
51                         minTypeDiffWeight = typeDiffWeight;
52                         ambiguousFactoryMethods = null;
53                     }
54                     // Find out about ambiguity: In case of the same type difference weight
55                     // for methods with the same number of parameters, collect such candidates
56                     // and eventually raise an ambiguity exception.
57                     // However, only perform that check in non-lenient constructor resolution mode,
58                     // and explicitly ignore overridden methods (with the same parameter signature).
59                     else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
60                             !mbd.isLenientConstructorResolution() &&
61                             paramTypes.length == factoryMethodToUse.getParameterCount() &&
62                             !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
63                         if (ambiguousFactoryMethods == null) {
64                             ambiguousFactoryMethods = new LinkedHashSet<>();
65                             ambiguousFactoryMethods.add(factoryMethodToUse);
66                         }
67                         ambiguousFactoryMethods.add(candidate);
68                     }
69                 }
70             }
71 
72             .....
73         return bw;
74     }

  每一个参数都需要解析,但是看这里不像没关系,继续往下走:就会看到

    private ArgumentsHolder createArgumentArray(String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {....//这下就是了,每个参数都被进行解析for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {....try {//我们的参数就是在这里被进行解析的--resolveAutowiredArgumentObject autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);args.rawArguments[paramIndex] = autowiredArgument;args.arguments[paramIndex] = autowiredArgument;args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();args.resolveNecessary = true;}catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);}}}//其他不重要的,直接忽略掉...return args;}

  开始解析的时看到了,我们需要把断言和过滤器列表都加在进来,那spring是如何加载的呢?是根据方法体内传入的类型找到所有实现了断言和过滤器工厂接口的类并且进行获取实例,我们仔细这些工厂的实现类,就会找到我们的使用的一些属性,比如我们例子中的PrefixPath过滤器和Path断言;

    protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {//主要的就是这个,beanNamesForTypeIncludingAncestors方法,该方法就是从bean工厂中获取所有当前类的实现实例名称,String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);...//遍历名称,进行实例化for (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}.....return result;}

 

   这下我们知道了,系统配置的断言和过滤器是如何被加载 的了,那我们还有一个问题,如果我自定义一个,如何被系统识别呢?并且怎么进行配置呢?不难发现我们之前看源码时,他是被spring通过找工厂实现类找到并且加载进来的,那我们自己实现工厂接口并且使用@Component注解,让spring加载进来不就的了吗?但是你会发现系统自定义的属性断言或者过滤器都有工厂名字的后缀,这是为什么呢?影响我们自定义 的类被加载到gateway中且生效吗?事实是会影响,那为什么影响呢?我们还是看源码。因为我们之前的类加载还没有看完,我们最开始的时候就找到了两个@bean 的自动加载,那这两个类实例化的时候都做了哪些工作,我们还没有细看;

    public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,List<RoutePredicateFactory> predicates,List<GatewayFilterFactory> gatewayFilterFactories,GatewayProperties gatewayProperties) {this.routeDefinitionLocator = routeDefinitionLocator;initFactories(predicates);gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory));this.gatewayProperties = gatewayProperties;}

  initFactories(predicates):这段代码主要是进行解析断言工厂实现类;并且放入一个Map中,

  gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory)):跟断言的代码几乎一样,因为没有其他多余的逻辑,所以没有封装到方法中,直接使用java8 的流特性,写完了遍历的过程。大家要注意一段代码就是factory.name(),这里使用了一个方法;

    default String name() {return NameUtils.normalizeRoutePredicateName(getClass());}

  主要就是把当前类包含工厂名字的部分去掉了,然后用剩下的字符串当key值,所以我们可以使用工厂名字做后坠,也可以不用,但是剩下的字符则是你要写进配置的关键字,不过博主基本都是按照系统自带属性一样,用的是工厂接口的名字做的后缀。

   好了,今天就讲解这么多,下次在讲解gateway接到请求后,是如何进行一步一步过滤的,何时进行断言校验的。一次不讲这么多,消化了就好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3249650.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

WDL(Wide Deep Learning for Recommender Systems)——Google经典CTR预估模型

一、文章简介 Wide & Deep Learning for Recommender Systems这篇文章介绍了一种结合宽线性模型和深度神经网络的方法&#xff0c;以实现推荐系统中的记忆和泛化。这种方法在Google Play商店的应用推荐系统中进行了评估&#xff0c;展示了其显著的性能提升。 推荐系统中的…

食堂采购系统开发:从需求分析到上线实施的完整指南

本篇文章&#xff0c;笔者将详细介绍食堂采购系统从需求分析到上线实施的完整过程&#xff0c;旨在为开发团队和管理者提供一个系统化的指南。 一、需求分析 1.用户需求 常见的需求包括&#xff1a; -采购计划管理 -供应商管理 -库存管理 -成本控制 -报表生成 2.系统功…

RK3568笔记四十:设备树

若该文为原创文章&#xff0c;转载请注明原文出处。 一、介绍 设备树 (Device Tree) 的作用就是描述一个硬件平台的硬件资源&#xff0c;一般描述那些不能动态探测到的设备&#xff0c;可以被动态探测到的设备是不需要描述。 设备树可以被 bootloader(uboot) 传递到内核&#x…

CentOS6minimal安装nginx-1.26.1.tar.gz 笔记240718

CentOS6安装新版nginx 240718, CentOS6.1-minimal 安装 nginx-1.26.1.tar.gz 下载 nginx-1.26.1.tar.gz 的页面 : https://nginx.org/en/download.html 下载 nginx-1.26.1.tar.gz : https://nginx.org/download/nginx-1.26.1.tar.gz CentOS6.1已过期, 给它更换yum源, 将下面…

SpringCloud------Sentinel(微服务保护)

目录 雪崩问题 处理方式!!!技术选型 Sentinel 启动命令使用步骤引入依赖配置控制台地址 访问微服务触发监控 限流规则------故障预防流控模式流控效果 FeignClient整合Sentinel线程隔离-------故障处理线程池隔离和信号量隔离​编辑 两种方式优缺点设置方式 熔断降级-----…

简述乐观锁和悲观锁——Java

悲观锁和乐观锁 悲观就是任何事都认为会往坏处发生&#xff0c;乐观就是认为任何事都会往好处发生。 打个比方&#xff0c;假如一个公司里只有一台打印机&#xff0c;如果多个人同时打印文件&#xff0c;可能出现混乱的问题&#xff0c;他的资料打印在了我的资料上&#xff0…

【视频讲解】神经网络、Lasso回归、线性回归、随机森林、ARIMA股票价格时间序列预测|附代码数据

全文链接&#xff1a;https://tecdat.cn/?p37019 分析师&#xff1a;Haopeng Li 随着我国股票市场规模的不断扩大、制度的不断完善&#xff0c;它在金融市场中也成为了越来越不可或缺的一部分。 【视频讲解】神经网络、Lasso回归、线性回归、随机森林、ARIMA股票价格时间序列…

Unity动画系统(4)

6.3 动画系统高级1-1_哔哩哔哩_bilibili p333- 声音组件添加 using System.Collections; using System.Collections.Generic; using UnityEngine; public class RobotAnimationController : MonoBehaviour { [Header("平滑过渡时间")] [Range(0,3)] publ…

AI智能名片S2B2C商城小程序在社群去中心化管理中的应用与价值深度探索

摘要&#xff1a;随着互联网技术的飞速发展&#xff0c;社群经济作为一种新兴的商业模式&#xff0c;正逐渐成为企业与用户之间建立深度连接、促进商业增长的重要途径。本文深入探讨了AI智能名片S2B2C商城小程序在社群去中心化管理中的应用&#xff0c;通过详细分析社群去中心化…

科普文:多线程如何使用CPU缓存?

一、前言 计算机的基础知识聊的比较少&#xff0c;但想要更好的理解多线程以及为后续多线程的介绍做铺垫&#xff0c;所以有必要单独开一篇来聊一下 CPU cache。 二、CPU 前面有一篇文章关于 CPU是如何进行计算 感兴趣的同学&#xff0c;可以先移步了解一下&#xff0c;不了…

连接Redis异常:JedisMovedDataException

redis.clients.jedis.exceptions.JedisMovedDataException: MOVED 5798 192.168.187.138:6379 在使用JAVA API连接redis的时候&#xff0c;出现了异常&#xff1a; 问题的原因 JAVA API实现是redis集群实现方式&#xff0c;而在配置文中就配置的是单结点的方式。 Moved表示使…

从人工巡检到智能防控:智慧油气田安全生产的新视角

一、背景需求 随着科技的飞速发展&#xff0c;视频监控技术已成为各行各业保障安全生产、提升管理效率的重要手段。特别是在油气田这一特殊领域&#xff0c;由于其工作环境复杂、安全风险高&#xff0c;传统的监控方式已难以满足实际需求。因此&#xff0c;基于视频监控AI智能…

NLP教程:1 词袋模型和TFIDF模型

文章目录 词袋模型TF-IDF模型词汇表模型 词袋模型 文本特征提取有两个非常重要的模型&#xff1a; 词集模型&#xff1a;单词构成的集合&#xff0c;集合自然每个元素都只有一个&#xff0c;也即词集中的每个单词都只有一个。 词袋模型&#xff1a;在词集的基础上如果一个单词…

springcolud学习04Ribbon

Ribbon Ribbon是一个用于构建分布式系统的开源项目&#xff0c;最初由Netflix开发。它是一个基于HTTP和TCP客户端负载均衡器&#xff0c;用于将客户端的请求分发到多个服务实例上&#xff0c;以提高系统的性能和可靠性。Ribbon提供了许多负载均衡算法和配置选项&#xff0c;可…

maven内网依赖包编译报错问题的一种解决方法

背景 外网开发时可以连接互联网&#xff0c;所以编译没有什么问题&#xff0c;但是将数据库、代码、maven仓库全部拷贝到内网&#xff0c;搭建内网环境之后&#xff0c;编译失败。 此依赖包的依赖层级图 maven镜像库配置使用拷贝到内网的本地库&#xff0c;配置如下&#xff…

WebRTC音视频-前言介绍

目录 效果预期 1&#xff1a;WebRTC相关简介 1.1&#xff1a;WebRTC和RTC 1.2&#xff1a;WebRTC前景和应用 2&#xff1a;WebRTC通话原理 2.1&#xff1a;媒体协商 2.2&#xff1a;网络协商 2.3&#xff1a;信令服务器 效果预期 1&#xff1a;WebRTC相关简介 1.1&…

24位动态信号采集卡8路同步音频震动信号采集IEPE采集卡USB8814

24位动态信号采集卡 音频震动信号采集USB8814实测演示 品牌&#xff1a;阿尔泰科技 产品概述&#xff1a; USB8814 是一款为测试音频和振动信号而设计的高精度数据采集卡。该板卡提供 8 路同步模拟输 入通道&#xff0c;24bit 分辨率&#xff0c;单通道采样速率zui高 204.8kSP…

4.定时器

原理 时钟源&#xff1a;定时器是内部时钟源&#xff08;晶振&#xff09;&#xff0c;计数器是外部计时长度&#xff1a;对应TH TL计数器初值寄存器(高八位,低八位)对应的中断触发函数 中断源中断处理函数Timer0Timer0_Routine(void) interrupt 1Timer1Timer1_Routine(void) …

css list布局 高端玩法

这种布局方式 通常父级item 使用display:flex; 子集list使用margin-right margin-bottom撑开距离 然后得纠结最后一个子集的margin什么的 有个新思路子集使用padding <div class"video-box"><div class"video-list" v-for"item in videoLis…

系统架构设计师教程(清华第二版) 第3章 信息系统基础知识-3.3 管理信息系统(MIS)-解读

系统架构设计师教程 第3章 信息系统基础知识-3.3 管理信息系统(MIS) 3.3.1 管理信息系统的概念3.3.1.1 部件组成3.3.1.2 结构分类3.3.1.2.1 开环结构3.3.1.2.2 闭环结构3.3.1.3 金字塔结构3.3.2 管理信息系统的功能3.3.3 管理信息系统的组成3.3.3.1 销售市场子系统3.3.3.2…