博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化
阅读量:6536 次
发布时间:2019-06-24

本文共 11592 字,大约阅读时间需要 38 分钟。

hot3.png

本文主要基于 Spring-Cloud-Gateway 2.0.X M4

摘要: 原创出处 「芋道源码」欢迎转载,保留摘要,谢谢!


???关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

1. 概述

本文主要分享 Spring Cloud Gateway 启动初始化的过程

在初始化的过程中,涉及到的组件会较多,本文不会细说,留到后面每篇文章针对每个组件详细述说。

那么这有什么意义呢?先对 Spring Cloud Gateway 内部的组件有整体的印象。


在官方提供的实例项目 spring-cloud-gateway-sample ,我们看到 GatewaySampleApplication 上有 @EnableAutoConfiguration 注解。因为该项目导入了 spring-cloud-gateway-core 依赖库,它会扫描 Spring Cloud Gateway 的配置。

在 包下,我们可以看到四个配置类 :

  • GatewayAutoConfiguration
  • GatewayClassPathWarningAutoConfiguration
  • GatewayLoadBalancerClientAutoConfiguration
  • GatewayRedisAutoConfiguration

它们的初始化顺序如下图 :


推荐 Spring Cloud 书籍

  • 请支持正版。下载盗版,等于主动编写低级 BUG
  • 程序猿DD ——
  • 周立 ——
  • 两书齐买,京东包邮。

推荐 Spring Cloud 视频

2. GatewayClassPathWarningAutoConfiguration

Spring Cloud Gateway 2.x 基于 Spring WebFlux 实现。

org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration ,用于检查项目是否正确导入 spring-boot-starter-webflux 依赖,而不是错误导入 spring-boot-starter-web 依赖。

点击链接 查看 GatewayClassPathWarningAutoConfiguration 的代码实现。

3. GatewayLoadBalancerClientAutoConfiguration

org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration ,初始化 LoadBalancerClientFilter ,点击 查看代码。

在 详细解析 LoadBalancerClientFilter 的代码实现。

4. GatewayRedisAutoConfiguration

org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration ,初始化 RedisRateLimiter 。

RequestRateLimiterGatewayFilterFactory 基于 RedisRateLimiter 实现网关的限流功能,在 详细解析相关的代码实现。

5. GatewayAutoConfiguration

org.springframework.cloud.gateway.config.GatewayAutoConfiguration ,Spring Cloud Gateway 核心配置类,初始化如下 :

  • NettyConfiguration
  • GlobalFilter
  • FilteringWebHandler
  • GatewayProperties
  • PrefixPathGatewayFilterFactory
  • RoutePredicateFactory
  • RouteDefinitionLocator
  • RouteLocator
  • RoutePredicateHandlerMapping
  • GatewayWebfluxEndpoint

组件关系交互如下图 :

5.1 网关的开启与关闭

从 GatewayAutoConfiguration 上的注解 @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) ,我们可以看出 :

  • 通过 spring.cloud.gateway.enabled 配置网关的开启与关闭。
  • matchIfMissing = true => 网关默认开启

5.2 初始化 NettyConfiguration

org.springframework.cloud.gateway.config.NettyConfiguration ,Netty 配置类。代码如下 :

1: @Configuration  2: @ConditionalOnClass(HttpClient.class)  3: protected static class NettyConfiguration {  4: 	@Bean // 1.2  5: 	@ConditionalOnMissingBean  6: 	public HttpClient httpClient(@Qualifier("nettyClientOptions") Consumer
options) { 7: return HttpClient.create(options); 8: } 9: 10: @Bean // 1.1 11: public Consumer
nettyClientOptions() { 12: return opts -> { 13: opts.poolResources(PoolResources.elastic("proxy")); 14: // opts.disablePool(); //TODO: why do I need this again? 15: }; 16: } 17: 18: @Bean // 1.3 19: public NettyRoutingFilter routingFilter(HttpClient httpClient) { 20: return new NettyRoutingFilter(httpClient); 21: } 22: 23: @Bean // 1.4 24: public NettyWriteResponseFilter nettyWriteResponseFilter() { 25: return new NettyWriteResponseFilter(); 26: } 27: 28: @Bean // 1.5 {@link org.springframework.cloud.gateway.filter.WebsocketRoutingFilter} 29: public ReactorNettyWebSocketClient reactorNettyWebSocketClient(@Qualifier("nettyClientOptions") Consumer
options) { 30: return new ReactorNettyWebSocketClient(options); 31: } 32: }
  • 每个 @Bean 注解后的数字为 Bean 的初始化顺序
  • 第 10 至 16 行 :创建一个类型为 java.util.Objects.Consumer 的 Bean 对象。该 Consumer 会将传入类型为 reactor.ipc.netty.options.HttpClientOptions.Builder 的参数 opts ,设置 optspoolResources 属性。
    • 调用 PoolResources.elastic("proxy") 方法,创建 name 属性为 "proxy"reactor.ipc.netty.resources.PoolResources 。其中 "proxy" 用于实际使用时,打印日志的标记
  • 第 4 至 8 行 :创建一个类型为 reactor.ipc.netty.http.client.HttpClient 的 Bean 对象。该 HttpClient 使用 Netty 实现的 Client 。
  • 第 18 至 21 行 :使用 HttpClient Bean ,创建一个类型为 org.springframework.cloud.gateway.filter.NettyRoutingFilter 的 Bean 对象。在 详细解析 NettyRoutingFilter 的代码实现。
  • 第 23 至 26 行 :创建一个类型为 org.springframework.cloud.gateway.filter.NettyWriteResponseFilter 的 Bean 对象。在 详细解析 NettyWriteResponseFilter 的代码实现。
  • 第 28 至 31 行 :创建一个类型为 org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient 的 Bean 对象,用于下文 WebsocketRoutingFilter 的 Bean 对象创建。

5.3 初始化 GlobalFilter

代码如下 :

1: @Bean // 2.1  2: public RouteToRequestUrlFilter routeToRequestUrlFilter() {  3: 	return new RouteToRequestUrlFilter();  4: }  5:   6: @Bean // 2.2  7: @ConditionalOnBean(DispatcherHandler.class)  8: public ForwardRoutingFilter forwardRoutingFilter(DispatcherHandler dispatcherHandler) {  9: 	return new ForwardRoutingFilter(dispatcherHandler); 10: } 11:  12: @Bean // 2.3 13: public WebSocketService webSocketService() { 14: 	return new HandshakeWebSocketService(); 15: } 16:  17: @Bean // 2.4 18: public WebsocketRoutingFilter websocketRoutingFilter(WebSocketClient webSocketClient, WebSocketService webSocketService) { 19: 	return new WebsocketRoutingFilter(webSocketClient, webSocketService); 20: }
  • 每个 @Bean 注解后的数字为 Bean 的初始化顺序
  • 第 1 至 4 行 :创建一个类型为 org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter 的 Bean 对象。在 详细解析 RouteToRequestUrlFilter 的代码实现。
  • 第 6 至 10 行 :创建一个类型为 org.springframework.cloud.gateway.filter.ForwardRoutingFilter 的 Bean 对象。在 详细解析 ForwardRoutingFilter 的代码实现。
  • 第 12 至 15 行 :创建一个类型为 org.springframework.web.reactive.socket.server.WebSocketService 的 Bean 对象。
  • 第 17 至 20 行 :创建一个类型为 org.springframework.cloud.gateway.filter.WebsocketRoutingFilter 的 Bean 对象。在 详细解析 WebsocketRoutingFilter 的代码实现。

5.4 初始化 FilteringWebHandler

当所有 org.springframework.cloud.gateway.filter.GlobalFilter 初始化完成时( 包括上面的 NettyRoutingFilter / NettyWriteResponseFilter ),创建一个类型为 org.springframework.cloud.gateway.handler.FilteringWebHandler 的 Bean 对象,代码如下 :

@Bean // 2.6public FilteringWebHandler filteringWebHandler(List
globalFilters) { return new FilteringWebHandler(globalFilters);}
  • 在 详细解析 FilteringWebHandler 的代码实现。

5.5 初始化 GatewayProperties

创建一个类型为 org.springframework.cloud.gateway.config.GatewayProperties 的 Bean 对象,用于加载配置文件配置的 RouteDefinition / FilterDefinition 。代码如下 :

@Bean // 2.7public GatewayProperties gatewayProperties() {    return new GatewayProperties();}
  • 在 详细解析 GatewayProperties 的代码实现。

5.6 初始化 PrefixPathGatewayFilterFactory

在 的【第 288 至 372 行】,创建 org.springframework.cloud.gateway.filter.factory 包下的 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory 接口的实现们。

后续我们会对每个 GatewayFilterFactory 的实现代码做详细解析。

5.7 初始化 RoutePredicateFactory

在 的【第 236 至 284 行】,创建 org.springframework.cloud.gateway.handler.predicate 包下的 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 接口的实现们。

后续我们会对每个 RoutePredicateFactory 的实现代码做详细解析。

5.8 初始化 RouteDefinitionLocator

代码如下 :

1: @Bean // 4.1  2: @ConditionalOnMissingBean  3: public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {  4: 	return new PropertiesRouteDefinitionLocator(properties);  5: }  6:   7: @Bean // 4.2  8: @ConditionalOnMissingBean(RouteDefinitionRepository.class)  9: public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() { 10: 	return new InMemoryRouteDefinitionRepository(); 11: } 12:  13: @Bean // 4.3 14: @Primary // 优先被注入 15: public RouteDefinitionLocator routeDefinitionLocator(List
routeDefinitionLocators) { 16: return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators)); 17: }
  • 每个 @Bean 注解后的数字为 Bean 的初始化顺序
  • 第 1 至 5 行 :使用 GatewayProperties Bean ,创建一个类型为 org.springframework.cloud.gateway.config.PropertiesRouteDefinitionLocator 的 Bean 对象。在 详细解析 PropertiesRouteDefinitionLocator 的代码实现。
  • 第 7 至 11 行 :创建一个类型为 org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository 的 Bean 对象。在 详细解析 InMemoryRouteDefinitionRepository 的代码实现。
  • 第 13 至 17 行 :使用上面创建的 RouteDefinitionLocator 的 Bean 对象们,创建一个类型为 org.springframework.cloud.gateway.route.CompositeRouteDefinitionLocator 的 Bean 对象。
    • 第 14 行的 @Primary 注解,用于下文注入类型为 RouteDefinitionLocator 的 Bean 对象时,使用该对象。点击 查看 @Primary 的详细介绍。

org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator ,基于 DiscoveryClient 注册发现的 RouteDefinitionLocator 实现类,需要手动引入配置,点击 查看。在 详细解析 DiscoveryClientRouteDefinitionLocator 的代码实现。

5.9 初始化 RouteLocator

代码如下 :

1: @Bean // 4.4  2: public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,  3: 											   List
GatewayFilters, 4: List
predicates, 5: RouteDefinitionLocator routeDefinitionLocator) { 6: return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties); 7: } 8: 9: @Bean // 4.5 10: @Primary 11: public RouteLocator routeLocator(List
routeLocators) { 12: return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators))); 13: }
  • 每个 @Bean 注解后的数字为 Bean 的初始化顺序
  • 第 1 至 7 行 :创建一个类型为 org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator 的 Bean 对象。在 详细解析 RouteDefinitionRouteLocator 的代码实现。
    • 此处的 routeDefinitionLocator 参数,使用了 @Primary 注解的 CompositeRouteDefinitionLocator 的 Bean 对象。
  • 第 9 至 13 行 :创建一个类型为 org.springframework.cloud.gateway.route.CachingRouteLocator 的 Bean 对象。该 Bean 对象内嵌 org.springframework.cloud.gateway.route.CompositeRouteLocator 对象。在 详细解析 CachingRouteLocator / CompositeRouteLocator 的代码实现。

另外,有如下两种方式实现自定义 RouteLocator :

  • 使用 Routes#locator()#build() 方法,创建 RouteLocator ,例子代码如下 :

    @Beanpublic RouteLocator customRouteLocator() {    //@formatter:off    return Routes.locator()			.route("test")				.predicate(host("**.abc.org").and(path("/image/png")))				.addResponseHeader("X-TestHeader", "foobar")				.uri("http://httpbin.org:80")			.route("test2")				.predicate(path("/image/webp"))				.add(addResponseHeader("X-AnotherHeader", "baz"))				.uri("http://httpbin.org:80")			.build();    @formatter:on}
    • 在 详细解析 org.springframework.cloud.gateway.route.Routes 的代码实现。
  • 使用 RouteLocatorDsl#gateway() 方法,创建 RouteLocator ,该方式使用 Kotlin 实现例子代码如下 :

    @Configurationclass AdditionalRoutes {	@Bean	fun additionalRouteLocator(): RouteLocator = gateway {		route(id = "test-kotlin") {			uri("http://httpbin.org:80")			predicate(host("kotlin.abc.org") and path("/image/png"))			add(addResponseHeader("X-TestHeader", "foobar"))		}	}}
    • 在 详细解析 org.springframework.cloud.gateway.route.RouteLocatorDsl 的代码实现。

5.10 初始化 RoutePredicateHandlerMapping

创建一个类型为 org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping 的 Bean 对象,用于查找匹配到 Route ,并进行处理。代码如下 :

@Beanpublic RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler,																   RouteLocator routeLocator) {    return new RoutePredicateHandlerMapping(webHandler, routeLocator);}
  • 在 详细解析 RoutePredicateHandlerMapping 的代码实现。

5.11 初始化 GatewayWebfluxEndpoint

创建一个类型为 org.springframework.cloud.gateway.actuate.GatewayWebfluxEndpoint 的 Bean 对象,提供管理网关的 HTTP API ,代码如下 :

@ManagementContextConfiguration@ConditionalOnProperty(value = "management.gateway.enabled", matchIfMissing = true)@ConditionalOnClass(Health.class)protected static class GatewayActuatorConfiguration {    @Bean    public GatewayWebfluxEndpoint gatewayWebfluxEndpoint(RouteDefinitionLocator routeDefinitionLocator, List
globalFilters, List
GatewayFilters, RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator) { return new GatewayWebfluxEndpoint(routeDefinitionLocator, globalFilters, GatewayFilters, routeDefinitionWriter, routeLocator); }}
  • 在 详细解析 GatewayWebfluxEndpoint 的代码实现。

666. 彩蛋

知识星球

是不是内心里面有种感觉,“劳资看了一堆构造函数”?

嘿嘿嘿,后面咱一篇一篇走起!

胖友,分享一波朋友圈可好!

转载于:https://my.oschina.net/sword4j/blog/1787820

你可能感兴趣的文章
用js实现table内容从下到上连续滚动
查看>>
基于ffmpeg的流媒体服务器
查看>>
项目积累——Blockingqueue,ConcurrentLinkedQueue,Executors
查看>>
JVM学习笔记(一)------基本结构
查看>>
活动目录之备份与恢复
查看>>
删除 Eclipse 的 configuration 目录
查看>>
ActiveX开发知多少?
查看>>
你不得不知道的Visual Studio 2012(3)- 创建Windows应用程序
查看>>
Android操作系统2.0制作备份
查看>>
To XSS or not ? 杂谈
查看>>
TFTP服务器在Cisco设备上的应用(上传、下载IOS)
查看>>
获得文件和文件夹的所有权
查看>>
烂泥:学习mysql数据库主从同步复制原理
查看>>
Java相对路径读取文件
查看>>
PostgreSQL 商用版本EPAS(阿里云ppas) 自动(postgresql.conf)参数计算与适配功能
查看>>
烂泥:学习ssh之ssh隧道应用
查看>>
Android TableLayout 常用的属性介绍及演示
查看>>
Ajax跨域访问XML数据的另一种方式——使用YQL查询语句
查看>>
[原创]让您的服务器不再有被挂马的烦恼---文件安全卫士
查看>>
流水线和PC指针
查看>>