spring-cloud-gateway之架构设计

spring-cloud-gateway作为cloud体系的一员,其设计思想非常巧妙,项目leader是spring开源主要作者之一的Spencer Gibb

一、项目pom依赖

我们首先从gateway的dependencies查看其所依赖项,gateway本身对spring-boot-starter有依赖,gateway在微服务架构体系当中也是以Java 进程的方式而存在,这样我们在做二次元开发时可以不需要再次依赖此项;gateway-core的源码采用流表达式编码,这里要求我们的jdk保持在1.8版本以上以及对reactor异步模型有初步认知;其次对eureka的引入,默认采用eureka为服务注册中心;还有其他的引入比如redis、hystrix等均为功能功能性必要依赖。

spring-cloud-gateway-core 依赖项截图

二、工程结构解读

如图工程代码结构非常的清晰和明确,这得益于作者的优秀设计思想,采用工厂模式、门面模式等优秀的代码设计。

spring-cloud-gateway 工程结构
  1. actuate
    actuate 包下GatewayControllerEndpoint.java是一个内嵌endpoint监控api管理类,方便通过api来观察当前的routes配置和filter配置信息;其中有个POST(/routes/{id})可以运行时添加route配置。spring-boot和spring-cloud内嵌的管理类api的设计初衷便是为了方便与管理类平台集成,比如spring-cloud-admin。


  2. config
    config包下是gateway工程配置类或者项目启动初始化类, 分类和命名都非常的清晰,通过类名便可知道其中的内部作用,其包内类图如图所示:


  • GatewayAutoConfiguration.java
    
    image.png

    GatewayAutoConfiguration类从头部注解可以了解其中的类加载顺序和依赖条件。
    Configuration注解是spring ioc的标准配置注入注解;spring.cloud.gateway.enabled配置默认是开启的,即只要引入了spring-cloud-gateway-starter便开启了网关;AutoConfigureBefore和AutoConfigureAfter是配置注入的前后顺序保证;ConditionalOnClass标注必须依赖的bean条件,RouteLocator、ForwardPathFilter等实例bean都是为WebFilter(DispatcherHandler) 服务的,而GatewayAutoConfiguration类则是负责RouteLocatorBuilder、RetryGatewayFilterFactory等全局单一实例注入的。这个与我们自己spring-boot项目中需要一个注入配置类的作用类似。

  • GatewayClassPathWarningAutoConfiguration.java
    

    GatewayClassPathWarningAutoConfiguration作用比较单一,是gateway工程启动过程中的一个加载检查机制,当绑定条件丢失时会有log警告输出。


    image.png
  • GatewayEnvironmentPostProcessor.java
    

    2.2.0-SNAPSHOT版本新增的一个配置类,用于操作进程内部全局环境变量的值,作用与spring-cloud-admin可以动态修改spring-boot的日志级别类是。

  • GatewayLoadBalancerClientAutoConfiguration.java
    

    负责LoadBalancerClientFilter(负载均衡过滤器,在下游服务分布式多实例情况下做请求负载路由)的初始化注入。

  • GatewayMetricsAutoConfiguration.java
    

    负责GatewayMetricsFilter(请求监控全局过滤器)初始化注入。

  • GatewayNoLoaBalancerClientAutoConfiguration.java
    

    2.2.0-SNAPSHOT新增配置类,其中声明了一个受保护的内部全局过滤器,在处理请求是没有负载均衡计算,当RibbonAutoConfiguration类缺失情况下才会启动,之前gateway工程必须依赖netflix.ribbon作为默认的负载均衡引入,在2.2.0正式版本发布之后将会取代这个限制,即默认可以不开启负载均衡。

  • GatewayProperties.java
    

    spring.cloud.gateway这个配置项下的配置信息定义。主要包括routes、defaultFilters。

  • GatewayRedisAutoConfiguration.java
    

    gateway的请求限流是通过redis + lua script 来实现的,此类作用不言而喻。

  • GlobalCorsProperties.java
    

    Http Cors层面的配置,通常采用默认即可,即http请求不做限制,可以google了解一下Cors。

  • LoadBalancerProperties.java
    

    结合负载均衡等过滤器使用,其中只有一个配置属性(private boolean use404)。

  • HttpClientProperties.java
    

    Gateway依赖webflux,其HttpClient默认丢弃了apache的HttpClient,而是采用的reactor-netty框架封装的HttpClient,采用的是异步编程模式,HttpClientProperties则是为HttpClient而配置的。

  • PropertiesRouteDefinitionLocator.java
    

    GatewayProperties的代理类。

  1. discovery
    discovery包其实跟config包作用很类似,主要是服务发现方面的配置以及服务发现逻辑实现。


    image.png
  • DiscoveryLocatorProperties.java
    

    配置实现类,srping.cloud.gateway.discovery.locator.enabled默认为false, 必须在配置文件将其配置为true,才能开启服务发现的功能;srping.cloud.gateway.discovery.locator.routeIdPrefix显式为下有路由服务添加一个前缀标识;其他配置项采用默认配置即可。

  • GatewayDiscoveryClientAutoConfiguration.java
    

    从代码来看,主要是两个注入方法discoveryClientRouteDefinitionLocator()和discoveryLocatorProperties();
    discoveryLocatorProperties()方法向IOC注入一个DiscoveryLocatorProperties类的实例,注意此方法初始化了默认的predicate和FilterDefinition,为具体的服务发现逻辑计算与转换(discoveryClient.getServices())备用。


    image.png
  • DiscoveryClientRouteDefinitionLocator.java
    

    DiscoveryClientRouteDefinitionLocator这个类可以认为是服务发现的一个代理类,其final类型的属性主要有DiscoveryClient、DiscoveryLocatorProperties,丛载实现getRouteDefinitions方法。


    image.png

    discoveryClient.getServices()从注册中心获取所有的服务;


    image.png

    默认注入的DiscoveryClient是一个代理client,其中注入了两个具体的实现类对象,分别是SimpleDicoveryClient和EurekaDiscoveryClient(这是netflix.eureka提供的实现,如果采用zk或者自己实现的注册中心作为服务发现服务需要自己实现DiscoveryClient这个接口来注入),SimpleDiscoveryClient是gateway自身进程实例的代理,eureka中的才能获取到注册中心的服务实例。
    discoveryClient.getServices()方法的第84行获取了所有的serviceInstance,然后在89行开始遍历所有的serviceInstance实例,将每个serviceInstance信息转换成对应的RouteDedinition对象,依次设置serviceId和利用正则表达式将serviceInstance的服务id转换成对应的路由uri,并转换出各个服务特有的predicate和filterDefinition(注意此方法返回结果有内存缓存,会定期做过期清理,默认服务发现间隔1分钟,不会每次服务调用都会调用此方法)。

  1. event
    此包定义进程的事件封装,所有类都继承至ApplicationEvent抽象类,这是spring框架的内部标准,这个标准也是继承了jdk的EventObject,至于集成spring开发的应用如果需要采用事件发布订阅或者观察者模式等最好也实现该抽象类;抽象类没有抽象方法的约束,只有一个时间戳的mark字段,对具体实现没有任何影响。


    image.png
  1. filter
    filter包是gateway的核心实现(代码解读放在后续文章)。
    filter包一级目录是全局过滤器的实现,均实现了GlobalFilter接口和Ordered接口;
    factory包下是基于工厂模式实现的工厂过滤器,为可配置的过滤器,可针对服务粒度进行可选配置,或者在代码中能够实现api级别的过滤;
    headers包针对Http header层面的过滤器,这正常情况运用不到;
    retelimit包下是基于redis+lua scriptde的限流实现。


    image.png
  2. handler
    此包下主要是Predicate类工厂声明,在配置路由设置断言的时候常用来断言path、header、method等(源码解读放在后续文章)。


    image.png
  1. route
    路由层的抽象与定义,这个与下游服务配置深度绑定,可以想象将一个服务实例抽象为一个RouteDefinition,然后为此route增加其predicate和filter等抽象配置。


    image.png
    image.png
  1. support
    工具包,里面有各种filter逻辑和配置初始化所用的工具类,等同于我们平常的util包。


    image.png

三、结语

本篇文章旨在剖析spring-cloud-gateway-core工程下的结构,总结下来其实我觉得最大的收获是开源作者对于代码的合理设计使得包结构非常的简洁清晰,值得广大Java爱好者学习,能够深化行为和命名注释至自己的code当中;其次对于actuate、config、discovery、event简单包下的源码做了解读,后续章节将会重点专注与filter、handler和route下源码的解读,也是gateway框架架构设计精华部分。

附:基于spring-cloud-gateway增强实现参考enhance-gateway

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务。但如果要将微服务架构运用到生产项目上,并且能够发挥...
    java菜阅读 2,938评论 0 6
  • 转载请标明出处:https://www.fangzhipeng.com本文出自方志朋的博客 在上一篇文章详细的介绍...
    方志朋阅读 2,593评论 0 14
  • 引言 全局过滤器无疑是作用于所有经过网关转发的请求的,对于设计者来说被设计成全局过滤器实现的功能组件也即是设计者认...
    Lance_Xu阅读 17,759评论 2 11
  • 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务。但如果要将微服务架构运用到生产项目上,并且能够发挥...
    程序员技术圈阅读 2,774评论 10 27
  • 一套四个表情包,好想养只狗狗啊T﹏T
    予恩阅读 340评论 0 0