API 网关

API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

  1. 客户端会多次请求不同的微服务,增加了客户端的复杂性。
  2. 存在跨域请求,在一定场景下处理相对复杂。
  3. 认证复杂,每个服务都需要独立认证。
  4. 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
  5. 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。

以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性,典型的架构图如图所示:

使用 API 网关后的优点如下:

  • 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
  • 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
  • 减少了客户端与各个微服务之间的交互次数。

API 网关选型

业界的情况:

我前面的文章<Netflix网关zuul(1.x和2.x)全解析>已经介绍了zuul1 和zuul2,现在就尝试从实例入手介绍一下spring cloud gateway

首先我们一步步实现一个最简单的网关例子

步骤1:在http://start.spring.io网站上创建一个spring-cloud-gateway-example项目,依赖spring-cloud-gateway,如下图所示

此时生产了一个spring-cloud-gateway-example的空项目包,pom.xml文件如下

<?xml version="1.0" encoding="UTF-8"?>
<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/> <!--lookup parent from repository--></parent><groupId>com.example</groupId><artifactId>spring-cloud-gateway-example</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-cloud-gateway-example</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><spring-cloud.version>Greenwich.RELEASE</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url></repository></repositories></project>

2.创建一个Route实例的配置类GatewayRoutes

packagecom.example.springcloudgatewayexample;importorg.springframework.cloud.gateway.route.RouteLocator;importorg.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;
@Configurationpublic classGatewayRoutes {@BeanpublicRouteLocator routeLocator(RouteLocatorBuilder builder) {returnbuilder.routes().route(r->r.path("/java/**").filters(f-> f.stripPrefix(1)).uri("http://localhost:8090/helloWorld")).build();}
}

当然,也可以不适用配置类,使用配置文件,如下图所示

spring:cloud:gateway:routes: - predicates:- Path=/java/**filters:- StripPrefix=1uri: "http://localhost:8090/helloWorld"

不过,为了调试方便,我们使用配置类方式。

此时项目已经完成,足够简单吧。

3.启动此项目

>>因api网关需要转发到一个服务上,本文为http://localhost:8090/helloWorld,那需要先启动我上文<spring boot整合spring5-webflux从0开始的实战及源码解析>,你也可以创建一个普通的web项目,启动端口设置为8090,然后启动。

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.3.RELEASE)2019-02-21 09:29:07.450 INFO 11704 --- [ main] c.e.demo.Spring5WebfluxApplication : Starting Spring5WebfluxApplication on DESKTOP-405G2C8 with PID 11704 (E:\workspaceForCloud\spring5-webflux\target\classes started by dell in E:\workspaceForCloud\spring5-webflux)
2019-02-21 09:29:07.455 INFO 11704 --- [ main] c.e.demo.Spring5WebfluxApplication : No active profile set, falling back to default profiles: default
2019-02-21 09:29:09.409 INFO 11704 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8090
2019-02-21 09:29:09.413 INFO 11704 --- [ main] c.e.demo.Spring5WebfluxApplication : Started Spring5WebfluxApplication in 2.304 seconds (JVM running for 7.311)

>>以spring boot方式启动spring-cloud-gateway-example项目,日志如下

2019-02-21 10:34:33.435  INFO 8580 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$1e059320] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying).   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.1.3.RELEASE)2019-02-21 10:34:33.767  INFO 8580 --- [           main] e.s.SpringCloudGatewayExampleApplication : No active profile set, falling back to default profiles: default
2019-02-21 10:34:34.219  INFO 8580 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=d98183ec-3e46-38ba-ba4c-e976a1017dce
2019-02-21 10:34:34.243  INFO 8580 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$1e059320] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-02-21 10:34:44.367  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [After]
2019-02-21 10:34:44.367  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Before]
2019-02-21 10:34:44.367  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Between]
2019-02-21 10:34:44.367  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Cookie]
2019-02-21 10:34:44.367  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Header]
2019-02-21 10:34:44.368  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Host]
2019-02-21 10:34:44.368  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Method]
2019-02-21 10:34:44.368  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Path]
2019-02-21 10:34:44.368  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Query]
2019-02-21 10:34:44.368  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [ReadBodyPredicateFactory]
2019-02-21 10:34:44.368  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [RemoteAddr]
2019-02-21 10:34:44.368  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Weight]
2019-02-21 10:34:44.368  INFO 8580 --- [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [CloudFoundryRouteService]
2019-02-21 10:34:44.920  INFO 8580 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2019-02-21 10:34:44.923  INFO 8580 --- [           main] e.s.SpringCloudGatewayExampleApplication : Started SpringCloudGatewayExampleApplication in 12.329 seconds (JVM running for 13.126)

4.测试,浏览器访问http://localhost:8080/java/helloWorld

返回hello world !

5.从上面的代码和配置及实例中,我们可以看出spring cloud gateway处理request请求的流程如下所示:

即在最前端,启动一个netty server(默认端口为8080)接受请求,然后通过Routes(每个Route由Predicate(等同于HandlerMapping)和Filter(等同于HandlerAdapter))处理后通过Netty Client发给响应的微服务。

那么在gateway本身最重要的应该是Route(Netty Server和Client已经封装好了),它由RouteLocatorBuilder构建,内部包含Predicate和Filter,

    private Route(String id, URI uri, int order, AsyncPredicate<ServerWebExchange> predicate, List<GatewayFilter>gatewayFilters) {this.id =id;this.uri =uri;this.order =order;this.predicate =predicate;this.gatewayFilters =gatewayFilters;}

那么我们就来探讨一下这两个组件吧

5.1.Predicate

Predicte由PredicateSpec来构建,主要实现有:

以path为例

    /*** A predicate that checks if the path of the request matches the given pattern*@parampatterns the pattern to check the path against.*                The pattern is a {@linkorg.springframework.util.PathMatcher} pattern*@returna {@linkBooleanSpec} to be used to add logical operators*/publicBooleanSpec path(String... patterns) {return asyncPredicate(getBean(PathRoutePredicateFactory.class).applyAsync(c->c.setPatterns(Arrays.asList(patterns))));}

PathRoutePredicateFactory中执行

@Overridepublic Predicate<ServerWebExchange>apply(Config config) {final ArrayList<PathPattern> pathPatterns = new ArrayList<>();synchronized (this.pathPatternParser) {pathPatternParser.setMatchOptionalTrailingSeparator(config.isMatchOptionalTrailingSeparator());config.getPatterns().forEach(pattern->{PathPattern pathPattern= this.pathPatternParser.parse(pattern);pathPatterns.add(pathPattern);});}return exchange ->{PathContainer path=parsePath(exchange.getRequest().getURI().getPath());Optional<PathPattern> optionalPathPattern =pathPatterns.stream().filter(pattern->pattern.matches(path)).findFirst();if(optionalPathPattern.isPresent()) {PathPattern pathPattern=optionalPathPattern.get();traceMatch("Pattern", pathPattern.getPatternString(), path, true);PathMatchInfo pathMatchInfo=pathPattern.matchAndExtract(path);putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables());return true;}else{traceMatch("Pattern", config.getPatterns(), path, false);return false;}};}

5.2.Filter

Filter分两种,一种GatewayFilter,一种GlobalFilter

5.2.1 GatewayFilter

GatewayFilter由GatewayFilterSpec构建,GatewayFilter的构建器

5.2.2 GlobalFilter

5.3 GlobalFilter和GatewayFilter的联系

FilteringWebHandler.GatewayFilterAdapter代理了GlobalFilter

6.总结

本文从一个spring-cloud-gateway实例入手,深入浅出的介绍了spring-cloud-gateway的组件,并从源码角度给出了实现的原理。

spring-cloud-gateway在最前端,启动一个netty server(默认端口为8080)接受请求,然后通过Routes(每个Route由Predicate(等同于HandlerMapping)和Filter(等同于HandlerAdapter))处理后通过Netty Client发给响应的微服务。

Predicate和Filter的各个实现定义了spring-cloud-gateway拥有的功能。

参考资料:

【1】https://www.infoq.cn/article/comparing-api-gateway-performances

【2】https://dzone.com/articles/spring-cloud-gateway-configuring-a-simple-route

转载于:https://www.cnblogs.com/davidwang456/p/10411451.html

从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析相关推荐

  1. spring cloud gateway 网关_微服务网关Spring Cloud Gateway全搞定

    一.微服务网关Spring Cloud Gateway 1.1 导引 文中内容包含:微服务网关限流10万QPS.跨域.过滤器.令牌桶算法. 在构建微服务系统中,必不可少的技术就是网关了,从早期的Zuu ...

  2. 【硬核】Spring Cloud Gateway(网关)

    概念 Gateway是基于异步非阻塞模型上进行开发的,有springcloud团队开发.用来代替Zuul. 近几个月收集了收集了N份精校过的PDF版的Java八股文大全,涉及Java后端的方方面面,分 ...

  3. 微服务网关spring cloud gateway入门详解

    1.API网关 API 网关是一个处于应用程序或服务( REST API 接口服务)之前的系统,用来管理授权.访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的 ...

  4. Spring Cloud(10)——新一代网关Spring Cloud Gateway

    文章目录 Spring Cloud(10)--新一代网关Spring Cloud Gateway 1.背景知识--API网关 2.Spring Cloud Gateway 详细概述 3.Spring ...

  5. Spring Cloud学习笔记—网关Spring Cloud Gateway官网教程实操练习

    Spring Cloud学习笔记-网关Spring Cloud Gateway官网教程实操练习 1.Spring Cloud Gateway介绍 2.在Spring Tool Suite4或者IDEA ...

  6. Spring Cloud Gateway网关

    Spring Cloud Gateway网关 1. 简介 Spring Cloud Gateway是Spring官网基于Spring 5.0. Spring Boot 2.0.Project Reac ...

  7. Spring Cloud Gateway网关实现短网址生成、解析、转发

    Spring Cloud Gateway网关实现短网址生成.解析.转发 1.概述 2.基础实现 3.路由处理HandlerFunction 4.配置路由 5.测试 1.概述 在一些生成二维码等场景中, ...

  8. 客快物流大数据项目(一百一十七):网关 Spring Cloud Gateway

    文章目录 网关 Spring Cloud Gateway 一.简介 1.功能特性

  9. Spring Cloud Gateway — 网关基本功能API暴露

    API网关 API网关是一种设计模式,一种在微服务体系下的经典构件.要了解最新API网关模式可以参考敖小剑写的<Service Mesh和Api Gateway关系深度探讨> 早期SOA阶 ...

最新文章

  1. 网络安全系列之五十 对Web主目录进行备份
  2. 从零开始开发JVM语言(十一)Lambda
  3. jackson 反序列化string_Java 中使用Jackson反序列化
  4. Launcher(待完善...)
  5. MySQL调优(八):查缺补漏(mysql的锁机制,读写分离,执行计划详解,主从复制原理)
  6. CSS: hover选择器的使用
  7. [react] 使用PropTypes和Flow有什么区别?
  8. LintCode 1816. 使结果不超过阈值的最小除数(二分查找)
  9. 释放囚犯(洛谷-P1622)
  10. 移动端的开发-视口-适配
  11. ansible基本模块-shell
  12. sql join on和不用join区别_图解 SQL 各种 JOIN,太有用了!
  13. Android TableLayout 表格布局
  14. 16. jQuery - 获取并设置 CSS 类
  15. C#获取dynamic(动态)或非动态实体的属性值
  16. 六、Linux企业级YUM软件管理
  17. 设计模式 ( 十二 ) 静态代理模式
  18. 简单循迹小车实验心得_简单循迹小车的制作
  19. pr基本剪辑操作/视频导出操作
  20. 微信聊天小程序——(五、添加好友)

热门文章

  1. python用numpy和pil处理图像成灰度图_「火炉炼AI」机器学习047-图像的直方图均衡化操作...
  2. TortoiseGit git push提示fatal: HttpRequestException encountered remote: Invalid username or password.
  3. spring boot第八讲
  4. laravel php配置,PHP Laravel框架路由配置及设置技巧全解
  5. 本科985末端去哪学计算机好,4所“985高校”,录取分较低,常被拿来捡漏!
  6. python rsa_python rsa加解密
  7. react ui框架_顶级React组件库推荐
  8. openssl 加密解密 指令_OpenSSL未来架构设计,3.0初步实现
  9. 第六代微型计算机是,AMD Carrizo第六代A系列处理器技术解析
  10. 验证码的产生 python