SpringCloud进阶(七)Getway

八 Getway

8.1 API 网关(API Gateway)

SpringCloud进阶(七)Getway_第1张图片

在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计、开发、测试、部署和管理。这时,各个独立部署单元可以用不同的开发测试团队维护,可以使用不同的编程语言和技术平台进行设计,这就要求必须使用一种语言和平 台无关的服务协议作为各个单元间的通讯方式。

SpringCloud进阶(七)Getway_第2张图片

  • 定义

网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问

API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。

  • 职能

SpringCloud进阶(七)Getway_第3张图片

  • 网关的分类与功能

SpringCloud进阶(七)Getway_第4张图片

8.2 GetWay

SpringCloud进阶(七)Getway_第5张图片

  • 定义

Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流

  • Why?
  • Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
  • Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。
  • 比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。
  • 比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。
  • 概念

SpringCloud进阶(七)Getway_第6张图片

SpringCloud进阶(七)Getway_第7张图片

SpringCloud进阶(七)Getway_第8张图片

8.3 网络模型对比

  • zuul 1.x模型

SpringCloud中所集成的Zuul版本,采用的是Tomcat容器,使用的是传统的Servlet IO处理模型。

  • Servlet生命周期?
  • servlet 由 servlet container 进行生命周期管理
  • container 启动时构造 servlet 对象并调用 servlet init() 进行初始化;
  • container 运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用service();
  • container 关闭时调用 servlet destory() 销毁servlet;
  • servlet是一个简单的网络IO模型,当请求进入servlet container时,servlet container就会为其绑定一个线程,在并发不高的场景下这种模型是适用的。但是一旦高并发(比如用jmeter压测),线程数量就会涨,而线程资源代价是昂贵的(上下文切换,内存消耗大)严重影响请求的处理时间。在一些简单业务场景下,不希望为每个request分配一个线程,只需要1个或几个线程就能应对极大并发的请求,这种业务场景下servlet模型没有优势
  • 所以Zuul 1.x是基于servlet之上的一个阻塞式处理模型,即spring实现了处理所有request请求的一个servlet(DispatcherServlet)并由该servlet阻塞式处理。所以SpringCloud Zuul无法摆脱servlet模型的弊端。

SpringCloud进阶(七)Getway_第9张图片

  • Gateway模型
  • Gateway支持 Reactor 和 WebFlux
  • 传统的Web框架,比如说:struts2,springmvc等都是基于Servlet API与servlet容器基础之上运行的。
    但是Servlet3.1之后有了异步非阻塞的支持,而WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的。相对与传统的Web框架来说,它可以运行在诸如Netty,Undertow及支持Servlet3.1的容器上。
  • Spring WebFlux 是 Spring 5.0引入的新的响应式框架,区别于Spring MVC,它不需要依赖Servlet API,它是完全异步非阻塞的,并且基于 Reactor 来实现响应式流规范
  • 原理

SpringCloud进阶(七)Getway_第10张图片

客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指 定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑

8.4 GetWay编写

  • 新建 cloud-getway-getway9527 模块
  • 导入依赖
<dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
        
        <dependency>
            <groupId>com.shugroupId>
            <artifactId>cloud-aplartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <scope>runtimescope>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>
  • 编写配置文件一
server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_routh    #路由的ID,没有固定规则但要求唯一,简易配合服务名
          uri: http://localhost:8007        #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/hystrix/ok/**       #断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_routh   #路由的ID,没有固定规则但要求唯一,简易配合服务名
          uri: http://localhost:8007          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/hystrix/timeout/**           #断言,路径相匹配的进行路由
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  • 编写配置类
package com.shu.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {
     
    /**
     * 配置一个id为route-name的路由规则,
     * 当访问地址http://localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei
     * @param routeLocatorBuilder
     * @return
     */
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
     
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();

        routes.route("path_route_01",
                r -> r.path("/guonei")
                        .uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
}

  • 编写主启动类
package com.shu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class GetWay9527 {
     
    public static void main(String[] args) {
     
        SpringApplication.run(GetWay9527.class);
    }
}

在这里插入图片描述

8.5 动态路由

  • 增加依赖
 <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
  • 修改配置文件
server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      #开启服务
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment_routh #payment_routh    #路由的ID,没有固定规则但要求唯一,简易配合服务名
          uri: lb://CLOUD-PROVIDER-HYSTRIX        #匹配后提供服务的路由地址,通过服务名调用
          predicates:
            - Path=/payment/hystrix/ok/**       #断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_routh   #路由的ID,没有固定规则但要求唯一,简易配合服务名
          uri: lb://CLOUD-PROVIDER-HYSTRIX          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/hystrix/timeout/**           #断言,路径相匹配的进行路由
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

在这里插入图片描述

8.6 Predicate 的使用

  • 时间匹配
@SpringBootTest
public class MyTest {
     

    public static void main(String[] args) {
     
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println(now);
    }
}
routes:
        - id: payment_routh #payment_routh    #路由的ID,没有固定规则但要求唯一,简易配合服务名
          uri: lb://CLOUD-PROVIDER-HYSTRIX        #匹配后提供服务的路由地址,通过服务名调用
          predicates:
            - Path=/payment/hystrix/ok/**       #断言,路径相匹配的进行路由
            - After=2021-03-07T16:28:34.711+08:00[Asia/Shanghai] #在这个时间之后,可以访问
            - Before=2021-03-07T16:28:34.711+08:00[Asia/Shanghai]  #在这个时间之后前,可以访问
            - Between= 2019-01-20T06:06:06+08:00[Asia/Shanghai],2021-03-07T16:28:34.711+08:00[Asia/Shanghai] #在这两个时间之间可以访问
  • Cookie 匹配
 routes:
        - id: payment_routh #payment_routh    #路由的ID,没有固定规则但要求唯一,简易配合服务名
          uri: lb://CLOUD-PROVIDER-HYSTRIX        #匹配后提供服务的路由地址,通过服务名调用
          predicates:
            - Path=/payment/hystrix/ok/**       #断言,路径相匹配的进行路由
            - Cookie=ityouknow, kee.e  #通过cookie进行匹配

SpringCloud进阶(七)Getway_第11张图片

  • 更多参考博客:https://blog.csdn.net/rain_web/article/details/102469745

8.7 Filter 的使用

  • 生命周期

Spring Cloud Gateway同zuul类似,有“pre”和“post”两种方式的filter。客户端的请求先经过“pre”类型的filter,然后将请求转发到具体的业务服务,比如上图中的user-service,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端。

SpringCloud进阶(七)Getway_第12张图片

与zuul不同的是,filter除了分为“pre”和“post”两种方式的filter外,在Spring Cloud Gateway中,filter从作用范围可分为另外两种,一种是针对于单个路由的gateway filter,它在配置文件中的写法同predict类似;另外一种是针对于所有路由的global gateway filer。现在从作用范围划分的维度来讲解这两种filter。

  • 内置过滤器
    SpringCloud进阶(七)Getway_第13张图片

  • 内置全局过滤器

SpringCloud进阶(七)Getway_第14张图片

  • 自定义全局过滤器
package com.shu.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

@Configuration
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
     
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
     
        log.info("***********come in MyLogGateWayFilter: "+new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");//每次进来后判断带不带uname这个key
        if(uname == null){
     
            log.info("*********用户名为null ,非法用户,o(╥﹏╥)o");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);    //uname为null非法用户
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
     
        return 0;
    }
}

更多参考博客:https://blog.csdn.net/qq_41211642/article/details/104881451

你可能感兴趣的:(SpringCloud进阶,过滤器,网关,spring,java,gateway)