最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringCloud Gateway動(dòng)態(tài)轉(zhuǎn)發(fā)后端服務(wù)實(shí)現(xiàn)過(guò)程講解

 更新時(shí)間:2023年03月28日 10:06:20   作者:QiHY  
這篇文章主要介紹了SpringCloud Gateway動(dòng)態(tài)轉(zhuǎn)發(fā)后端服務(wù)實(shí)現(xiàn)過(guò)程,簡(jiǎn)單的路由轉(zhuǎn)發(fā)可以通過(guò)SpringCloudGateway的配置文件實(shí)現(xiàn),在一些業(yè)務(wù)場(chǎng)景種,會(huì)需要?jiǎng)討B(tài)替換路由配置中的后端服務(wù)地址,單純靠配置文件無(wú)法滿(mǎn)足這種需求

前言

API網(wǎng)關(guān)的核心功能是統(tǒng)一流量入口,實(shí)現(xiàn)路由轉(zhuǎn)發(fā),SpringCloudGateway是API網(wǎng)關(guān)開(kāi)發(fā)的技術(shù)之一,此外比較流行的還有Kong和ApiSix,這2個(gè)都是基于OpenResty技術(shù)棧。

簡(jiǎn)單的路由轉(zhuǎn)發(fā)可以通過(guò)SpringCloudGateway的配置文件實(shí)現(xiàn),在一些業(yè)務(wù)場(chǎng)景種,會(huì)需要?jiǎng)討B(tài)替換路由配置中的后端服務(wù)地址,單純靠配置文件無(wú)法滿(mǎn)足這種需求。

本文介紹一種將路由配置保存到數(shù)據(jù)庫(kù)中,可以根據(jù)接口請(qǐng)求的特定條件,從數(shù)據(jù)庫(kù)中動(dòng)態(tài)讀取后端服務(wù)地址,實(shí)現(xiàn)靈活轉(zhuǎn)發(fā)。

具體的代碼參照 示例項(xiàng)目 https://github.com/qihaiyan/springcamp/tree/master/spring-cloud-gateway

一、概述

通過(guò)把SpringCloudGateway的相關(guān)路由配置規(guī)則保存到數(shù)據(jù)庫(kù)中,可以動(dòng)態(tài)的靈活調(diào)整路由。在本文的實(shí)現(xiàn)中,我們通過(guò)請(qǐng)求header中的特定值,動(dòng)態(tài)選擇對(duì)應(yīng)的后端服務(wù)地址。

二、項(xiàng)目中加入依賴(lài)

在項(xiàng)目的gradle中增加依賴(lài)關(guān)系。

build.gradle:

plugins {
    id 'org.springframework.boot' version '3.0.2'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'cn.springcamp'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    testCompileOnly {
        extendsFrom testAnnotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation "org.springframework.boot:spring-boot-starter-json"
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
    implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'io.r2dbc:r2dbc-h2'
    annotationProcessor 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
    testImplementation "org.springframework.boot:spring-boot-starter-test"
    testImplementation 'org.junit.vintage:junit-vintage-engine'
    testImplementation 'io.projectreactor:reactor-test'
    testImplementation 'com.h2database:h2'
    testImplementation 'io.r2dbc:r2dbc-h2'
    testImplementation 'org.junit.vintage:junit-vintage-engine'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:2022.0.1"
    }
}

test {
    useJUnitPlatform()
}

由于SpringCloudGateway基于SpringWebFlux技術(shù)構(gòu)建,所以依賴(lài)中的數(shù)據(jù)庫(kù)配置需要使用r2dbc 。

三、配置文件

示例程序首選通過(guò)配置文件對(duì)路由進(jìn)行基本配置,配置文件代碼:

spring:
  r2dbc:
    url: r2dbc:h2:mem:///testdb?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password:
  cloud:
    gateway:
      routes:
        - id: routeOne
          predicates:
            - Path=/route1/**
          uri: no://op
          filters:
            - UriHostPlaceholderFilter=10001
        - id: routeTwo
          predicates:
            - Path=/route2/**
          uri: no://op
          filters:
            - UriHostPlaceholderFilter=10001

配置文件中配置了2個(gè)路由,對(duì)應(yīng)的接口地址路徑分別是 /route1/**Path=/route2/**,路徑中的 ***表示模糊匹配,只要是以 /route1/為前綴的路徑都可以被訪問(wèn)到。

后端服務(wù)地址配置了一個(gè)無(wú)意的地址: uri: no://op,因?yàn)槲覀兊奶幚磉壿嫊?huì)通過(guò)從數(shù)據(jù)庫(kù)中讀取配置來(lái)動(dòng)態(tài)替換后端服務(wù)地址。

四、動(dòng)態(tài)路由數(shù)據(jù)存儲(chǔ)格式

我們通過(guò) ROUTE_FILTER_ENTITY這個(gè)數(shù)據(jù)庫(kù)表來(lái)存儲(chǔ)接口后端服務(wù)配置數(shù)據(jù)。表結(jié)構(gòu)為:

CREATE TABLE "ROUTE_FILTER_ENTITY"
(
   id VARCHAR(255) PRIMARY KEY,
   route_id VARCHAR(255),  -- 路由ID,對(duì)應(yīng)配置文件中的 ```id```配置項(xiàng)
   code VARCHAR(255), -- 接口請(qǐng)求header中的code參數(shù)的值
   url VARCHAR(255) -- 后端服務(wù)地址
);

當(dāng)客戶(hù)端訪問(wèn) /route1/test接口時(shí),根據(jù)配置文件的路由配置,SpringCloudGateway 會(huì)命中 id: routeOne這個(gè)路由規(guī)則,這個(gè)規(guī)則對(duì)應(yīng)的后端服務(wù)地址是 uri: no://op,并不是我們期望的真實(shí)后端服務(wù)地址。

因此,我們需要讀取到真實(shí)的后端服務(wù)地址,并將請(qǐng)求轉(zhuǎn)發(fā)到這個(gè)地址。跟據(jù) routeId 和 接口請(qǐng)求header中的code參數(shù)的值,就可以從 ROUTE_FILTER_ENTITY 表中查到對(duì)應(yīng)的后端服務(wù)地址 url這個(gè)字段的值。

我們已經(jīng)讀取到了后端服務(wù)地址,還需要將請(qǐng)求轉(zhuǎn)發(fā)到這個(gè)地址,下面介紹轉(zhuǎn)發(fā)的方法。

五、后端服務(wù)動(dòng)態(tài)轉(zhuǎn)發(fā)

動(dòng)態(tài)轉(zhuǎn)發(fā)通過(guò)自定義 filter 的方式實(shí)現(xiàn),自定義 filter 代碼如下:

@Component
public class UriHostPlaceholderFilter extends AbstractGatewayFilterFactory<UriHostPlaceholderFilter.Config> {
    @Autowired
    private RouteFilterRepository routeFilterRepository;
    public UriHostPlaceholderFilter() {
        super(Config.class);
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("order");
    }
    @Override
    public GatewayFilter apply(Config config) {
        return new OrderedGatewayFilter((exchange, chain) -> {
            String code = exchange.getRequest().getHeaders().getOrDefault("code", new ArrayList<>()).stream().findFirst().orElse("");
            String routeId = exchange.getAttribute(GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR);
            if (StringUtils.hasText(code)) {
                String newurl;
                try {
                    newurl = routeFilterRepository.findByRouteIdAndCode(routeId, code).toFuture().get().getUrl();
                } catch (InterruptedException | ExecutionException e) {
                    throw new RuntimeException(e);
                }
                if (StringUtils.hasText(exchange.getRequest().getURI().getQuery())) {
                    newurl = newurl + "?" + exchange.getRequest().getURI().getQuery();
                }
                URI newUri = null;
                try {
                    newUri = new URI(newurl);
                } catch (URISyntaxException e) {
                    log.error("uri error", e);
                }
                exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newUri);
            }
            return chain.filter(exchange);
        }, config.getOrder());
    }
    @Data
    @NoArgsConstructor
    public static class Config {
        private int order;
        public Config(int order) {
            this.order = order;
        }
    }
}

通過(guò)擴(kuò)展 AbstractGatewayFilterFactory 類(lèi),我們自定義了 UriHostPlaceholderFilter 這個(gè) filter 。

代碼的核心邏輯在 apply 方法中。

首先通過(guò) String code = exchange.getRequest().getHeaders().getOrDefault("code", new ArrayList<>()).stream().findFirst().orElse("")可以獲取到接口請(qǐng)求 header 中 code 這個(gè)參數(shù)的值。

再通過(guò) String routeId = exchange.getAttribute(GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR)可以獲取到 routeId 。

最后通過(guò) newurl = routeFilterRepository.findByRouteIdAndCode(routeId, code).toFuture().get().getUrl()就可以從數(shù)據(jù)庫(kù)中讀取到配置好的后端服務(wù)地址。

拿到后端服務(wù)地址后, 通過(guò)調(diào)用 exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newUri);將請(qǐng)求轉(zhuǎn)發(fā)到對(duì)應(yīng)的地址。

六、單元測(cè)試

在單元測(cè)試代碼中,我們預(yù)置了一條后端服務(wù)動(dòng)態(tài)配置數(shù)據(jù):

insert into ROUTE_FILTER_ENTITY values('1','routeOne','alpha','http://httpbin.org/anything')

然后模擬請(qǐng)求 /route1/test?a=test這個(gè)接口,根據(jù)我們的配置,請(qǐng)求會(huì)被轉(zhuǎn)發(fā)到 http://httpbin.org/anything。

執(zhí)行單元測(cè)試后,可以從日志中發(fā)現(xiàn),接口返回的數(shù)據(jù)是 http://httpbin.org/anything 這個(gè)后端服務(wù)返回的數(shù)據(jù)。

當(dāng)我們希望調(diào)整后端服務(wù)地址時(shí),只需要把 ROUTE_FILTER_ENTITY 表中的這條配置數(shù)據(jù)中的 url 字段改成其它的任何服務(wù)地址即可,大大增加了程序的靈活度。

到此這篇關(guān)于SpringCloud Gateway動(dòng)態(tài)轉(zhuǎn)發(fā)后端服務(wù)實(shí)現(xiàn)過(guò)程講解的文章就介紹到這了,更多相關(guān)SpringCloud Gateway動(dòng)態(tài)轉(zhuǎn)發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何使用HttpClient發(fā)送java對(duì)象到服務(wù)器

    如何使用HttpClient發(fā)送java對(duì)象到服務(wù)器

    這篇文章主要介紹了如何使用HttpClient發(fā)送java對(duì)象到服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • java 簡(jiǎn)單的計(jì)算器程序?qū)嵗a

    java 簡(jiǎn)單的計(jì)算器程序?qū)嵗a

    這篇文章主要介紹了java 簡(jiǎn)單的計(jì)算器程序?qū)嵗a的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Java調(diào)用setStroke()方法設(shè)置筆畫(huà)屬性的語(yǔ)法

    Java調(diào)用setStroke()方法設(shè)置筆畫(huà)屬性的語(yǔ)法

    這篇文章主要介紹了Java調(diào)用setStroke()方法設(shè)置筆畫(huà)屬性的語(yǔ)法,如何改變線(xiàn)條的粗細(xì)、虛實(shí)和定義線(xiàn)段端點(diǎn)的形狀、風(fēng)格等,需要的朋友可以參考下
    2017-09-09
  • 淺析Spring基于注解的AOP

    淺析Spring基于注解的AOP

    Spring是一個(gè)廣泛應(yīng)用的框架,SpringAOP則是Spring提供的一個(gè)標(biāo)準(zhǔn)易用的aop框架,依托Spring的IOC容器,提供了極強(qiáng)的AOP擴(kuò)展增強(qiáng)能力,對(duì)項(xiàng)目開(kāi)發(fā)提供了極大地便利
    2022-11-11
  • Java優(yōu)化重復(fù)冗余代碼的8種方式總結(jié)

    Java優(yōu)化重復(fù)冗余代碼的8種方式總結(jié)

    日常開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到一些重復(fù)代碼,最近小編優(yōu)化了一些系統(tǒng)中的重復(fù)代碼,用了好幾種的方式,感覺(jué)挺有用的,所以本文給大家講講優(yōu)化重復(fù)代碼的幾種方式
    2023-08-08
  • java中l(wèi)ong數(shù)據(jù)類(lèi)型轉(zhuǎn)換為int類(lèi)型

    java中l(wèi)ong數(shù)據(jù)類(lèi)型轉(zhuǎn)換為int類(lèi)型

    這篇文章主要講解Java中基本數(shù)據(jù)類(lèi)型,java long 類(lèi)型與其java int類(lèi)型的轉(zhuǎn)換的幾種方法,希望能給大家做一個(gè)參考
    2016-07-07
  • Java中toString函數(shù)的使用示例代碼

    Java中toString函數(shù)的使用示例代碼

    toString()函數(shù)用于將當(dāng)前對(duì)象以字符串的形式返回,比如我定義了一個(gè)User類(lèi),創(chuàng)建了一個(gè)user對(duì)象,然后使用相應(yīng)命令去打印user對(duì)象,本文結(jié)合示例代碼介紹了toString函數(shù)的使用,需要的朋友可以參考下
    2024-02-02
  • SpringMvc+Mybatis+Pagehelper分頁(yè)詳解

    SpringMvc+Mybatis+Pagehelper分頁(yè)詳解

    這篇文章主要介紹了SpringMvc+Mybatis+Pagehelper分頁(yè)詳解,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下的相關(guān)資料
    2017-01-01
  • 一個(gè)簡(jiǎn)單的Spring容器初始化流程詳解

    一個(gè)簡(jiǎn)單的Spring容器初始化流程詳解

    這篇文章主要給大家介紹了一個(gè)簡(jiǎn)單的Spring容器初始化流程的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java 將Excel轉(zhuǎn)為OFD格式(方法步驟)

    Java 將Excel轉(zhuǎn)為OFD格式(方法步驟)

    OFD是一種開(kāi)放版式文檔是我國(guó)國(guó)家版式文檔格式標(biāo)準(zhǔn),本文通過(guò)Java后端程序代碼展示如何將Excel轉(zhuǎn)為OFD格式,分步驟給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2021-12-12

最新評(píng)論

乌兰县| 鄂托克旗| 莲花县| 贡嘎县| 全州县| 崇州市| 临城县| 社旗县| 阿巴嘎旗| 旬邑县| 务川| 融水| 肥西县| 新乡市| 嘉黎县| 甘孜县| 芮城县| 阿拉尔市| 宜川县| 洛隆县| 上虞市| 河北省| 儋州市| 灵宝市| 高州市| 广宁县| 法库县| 金阳县| 会昌县| 宁明县| 蓝田县| 岑溪市| 基隆市| 延寿县| 阿勒泰市| 呼和浩特市| 石柱| 普兰店市| 定安县| 库尔勒市| 崇文区|