溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何解析構(gòu)建Spring Cloud Gateway網(wǎng)關(guān)實戰(zhàn)及原理

發(fā)布時間:2021-10-20 10:30:10 來源:億速云 閱讀:130 作者:柒染 欄目:大數(shù)據(jù)

今天就跟大家聊聊有關(guān)如何解析構(gòu)建Spring Cloud Gateway網(wǎng)關(guān)實戰(zhàn)及原理,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

API 網(wǎng)關(guān)

API 網(wǎng)關(guān)出現(xiàn)的原因是微服務(wù)架構(gòu)的出現(xiàn),不同的微服務(wù)一般會有不同的網(wǎng)絡(luò)地址,而外部客戶端可能需要調(diào)用多個服務(wù)的接口才能完成一個業(yè)務(wù)需求,如果讓客戶端直接與各個微服務(wù)通信,會有以下的問題:

  1. 客戶端會多次請求不同的微服務(wù),增加了客戶端的復(fù)雜性。

  2. 存在跨域請求,在一定場景下處理相對復(fù)雜。

  3. 認證復(fù)雜,每個服務(wù)都需要獨立認證。

  4. 難以重構(gòu),隨著項目的迭代,可能需要重新劃分微服務(wù)。例如,可能將多個服務(wù)合并成一個或者將一個服務(wù)拆分成多個。如果客戶端直接與微服務(wù)通信,那么重構(gòu)將會很難實施。

  5. 某些微服務(wù)可能使用了防火墻 / 瀏覽器不友好的協(xié)議,直接訪問會有一定的困難。

以上這些問題可以借助 API 網(wǎng)關(guān)解決。API 網(wǎng)關(guān)是介于客戶端和服務(wù)器端之間的中間層,所有的外部請求都會先經(jīng)過 API 網(wǎng)關(guān)這一層。也就是說,API 的實現(xiàn)方面更多的考慮業(yè)務(wù)邏輯,而安全、性能、監(jiān)控可以交由 API 網(wǎng)關(guān)來做,這樣既提高業(yè)務(wù)靈活性又不缺安全性,典型的架構(gòu)圖如圖所示:

如何解析構(gòu)建Spring Cloud Gateway網(wǎng)關(guān)實戰(zhàn)及原理

使用 API 網(wǎng)關(guān)后的優(yōu)點如下:

  • 易于監(jiān)控。可以在網(wǎng)關(guān)收集監(jiān)控數(shù)據(jù)并將其推送到外部系統(tǒng)進行分析。

  • 易于認證??梢栽诰W(wǎng)關(guān)上進行認證,然后再將請求轉(zhuǎn)發(fā)到后端的微服務(wù),而無須在每個微服務(wù)中進行認證。

  • 減少了客戶端與各個微服務(wù)之間的交互次數(shù)。

API 網(wǎng)關(guān)選型

業(yè)界的情況:

如何解析構(gòu)建Spring Cloud Gateway網(wǎng)關(guān)實戰(zhàn)及原理

此時生產(chǎn)了一個spring-cloud-gateway-example的空項目包,pom.xml文件如下


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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.創(chuàng)建一個Route實例的配置類GatewayRoutes


package com.example.springcloudgatewayexample;

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 GatewayRoutes {
    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r ->
                        r.path("/java/**")
                                .filters(
                                        f -> f.stripPrefix(1)
                                )
                                .uri("http://localhost:8090/helloWorld")
                )
                .build();
    }
}


當(dāng)然,也可以不適用配置類,使用配置文件,如下圖所示


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


不過,為了調(diào)試方便,我們使用配置類方式。

此時項目已經(jīng)完成,足夠簡單吧。

3.啟動此項目

  >>因api網(wǎng)關(guān)需要轉(zhuǎn)發(fā)到一個服務(wù)上,本文為http://localhost:8090/helloWorld,那需要先啟動我上文<spring boot整合spring5-webflux從0開始的實戰(zhàn)及源碼解析>,你也可以創(chuàng)建一個普通的web項目,啟動端口設(shè)置為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發(fā)給響應(yīng)的微服務(wù)。

那么在gateway本身最重要的應(yīng)該是Route(Netty Server和Client已經(jīng)封裝好了),它由RouteLocatorBuilder構(gòu)建,內(nèi)部包含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來構(gòu)建,主要實現(xiàn)有:

如何解析構(gòu)建Spring Cloud Gateway網(wǎng)關(guān)實戰(zhàn)及原理

以path為例

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

PathRoutePredicateFactory中執(zhí)行

@Override
    public 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構(gòu)建,GatewayFilter的構(gòu)建器

 如何解析構(gòu)建Spring Cloud Gateway網(wǎng)關(guān)實戰(zhàn)及原理

5.3 GlobalFilter和GatewayFilter的聯(lián)系

FilteringWebHandler.GatewayFilterAdapter代理了GlobalFilter

6.總結(jié)

  本文從一個spring-cloud-gateway實例入手,深入淺出的介紹了spring-cloud-gateway的組件,并從源碼角度給出了實現(xiàn)的原理。

   spring-cloud-gateway在最前端,啟動一個netty server(默認端口為8080)接受請求,然后通過Routes(每個Route由Predicate(等同于HandlerMapping)和Filter(等同于HandlerAdapter))處理后通過Netty Client發(fā)給響應(yīng)的微服務(wù)。

 Predicate和Filter的各個實現(xiàn)定義了spring-cloud-gateway擁有的功能。

看完上述內(nèi)容,你們對如何解析構(gòu)建Spring Cloud Gateway網(wǎng)關(guān)實戰(zhàn)及原理有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI