[SpringCloud]Gateway入門

Gateway

Gateway和Zuul的理念差別

SpringCloud中集成的Zuul版本,採用的是Tomcat容器,使用的是傳統的Servlet IO處理模型。即:

container啓動的時候構造Servlet對象並調用Servlet.init()方法進行初始化。          container運行時接收請求,併爲每一個請求分配一個線程(一般從線程池獲取空閒線程),然後調用service()。          container關閉時調用Servlet.destroy()銷燬Servlet。

這樣的模式的缺點是,併發量高的情況下,大量的Servlet產生,從而綁定了大量的線程,而線程的資源實際上是很昂貴的,上下文的切換和內存的消耗會導致請求的處理時間延長。

而Gateway的底層使用的是netty和webflux,webflux是一個典型的非阻塞異步框架,核心是基於Reactor的相關API實現的,相對於傳統的Web框架來說,可以運行在諸如netty,undertow及支持Servlet3.1的容器上。

Gateway的三大核心概念

路由Route

Route是構建網關的基本模塊,由ID,目標URI,一系列的斷言和過濾器組成,如果斷言爲true則匹配這個路由。

斷言Predicate

參考的是java8中的java.util.function.Prediacate,開發人員可以匹配HTTP請求中的所有內容,如果請求和斷言相匹配則進行路由。

過濾器Filter

指的是Spring框架中的GatewayFilter的實例,使用過濾器,可以在請求路由前或者之後對請求進行修改。

Gateway工作流程

客戶端向SpringCloudGateway發出請求,然後在Gateway Handler Mapping中找到與請求相匹配的路由,將其發送到Gateway Web Handler,Handler再通過制定的過濾器來將請求發送到我們實際的服務執行業務邏輯,然後返回。簡單的老說,它相當於一個門衛,擋在我們的服務之前,在請求到達我們的服務的時候能夠做一些前置的處理,對於客戶來說背後的服務實際上是屏蔽的,與我們交互的是網關。

GateWay的基本使用

插一句話,最近剛參加工作,深感比在學校的時候要操心的地方要多得多,留給自己學習的時間也遠遠沒有學校多,只能趁週六週末來充電,實際上這個博客在上個月月底就已經起草,斷斷續續沒寫幾個字,而且Gateway的基本的東西也沒學完,所以一直拖到今天,今天也不打算把Gateway學個底朝天,只打算總結一下之前學的基本的東西,更多東西還是要去實際項目中用再能總結出來,就先這樣吧。
在寫Gateway的模塊之前,事實上肯定至少有一個服務和一個註冊中心的,這裏也不講Eureka和那個無關緊要的服務了。

配置Gateway的依賴

    <dependencies>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>cn.izzer</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>1.0</version>
        </dependency>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

yml配置

這裏主要是通過配置文件來配置一些映射,還有定義註冊中心地址什麼的,之後還有通過代碼來配置全局的過濾器等等。

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #開啓動態路由
      routes:
        - id: payment_routh1
          uri: http://localhost:8001
          predicates:
            - Path=/payment/get/** #配置路徑映射
            #- After=2020-08-14T22:44:44.829+08:00[Asia/Shanghai] 主要檢測時間
            #- Cookie=username,zzyy 檢測cookie,可以用curl進行模擬
            #- Header=X-Request-Id,\d+ #請求頭要有X-Request-Id屬性並且值爲整數的正則表達式
        - id: payment_routh2
          uri: http://localhost:8001
          predicates:
            - Path=/payment
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
      register-with-eureka: true
      fetch-registry: true
      service-url:
        defaultZone: http://localhost:7001/eureka

上面是配置了路徑映射,發起請求的時間攔截,cookie等等,時間的設置需要調用ZoneDateTime來得到。如下:

    @Test
    public void timeZoneTest(){
        ZonedDateTime time = ZonedDateTime.now();
        System.out.println(time);
    }

這裏演示一下Cookie和Header的測試,因爲這裏用到curl,我很少用這個東西,都是用postman,今天來漲漲知識。
avatar
然後是測試Header(亂碼了......)
avatar
官網上還有許多相類似的配置,就不一一展示了,也沒多大意義。接下來是用代碼實現路由配置。主要用到的是RouteLocatorBuilder.Builder。用@Configuration加上註解即可。

@Configuration
public class GateWayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
        //這裏是將網關服務的/guonei映射到百度新聞的國內新聞版塊。
        RouteLocatorBuilder.Builder builder = routeLocatorBuilder.routes();
        builder.route("path_route_atguigu",r->r.path("/guonei").uri("http://news.baidu.com/guonei"));
        return builder.build();
    }
}

測試效果:
avatar

Filter組件

物如其名,做過濾用的,這裏演示一下全局判斷接口傳入的字段(在實際工作這個不要亂用)。主要是要實現GlobalFilter和Ordered接口,然後在裏面加上自己的業務邏輯。我這裏簡單判斷一下uname字段是否傳入。

@Component
@Slf4j
public class GlobalGatewayFilter implements GlobalFilter,Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("------- come into global filter------");
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if (uname == null){
            log.info("---------uname is null ----- ");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

傳入uname的情況:
avatar
沒有傳入的情況:
avatar

參考

B站上的SpringCloud,適合跟着做個demo入門
同步博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章