Spring Cloud Gateway組件的三種使用方式實(shí)例詳解
??前言
Spring Cloud Gateway是 Spring 官方基于 Spring5.0 、 SpringBoot2.0 和 Project Reactor 等技術(shù)開發(fā)的網(wǎng)關(guān)旨在為微服務(wù)框架提供一種簡單而有效的統(tǒng)一的API 路由管理方式,統(tǒng)一訪問接口。
Spring Cloud Gateway作為 Spring Cloud 生態(tài)體系中的網(wǎng)關(guān),目標(biāo)是替代 Netflix 的 Zuul ,其不僅提供統(tǒng) 一的路由方式,并且基于Filter 鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全、監(jiān)控 / 埋點(diǎn)和限流等等,而且它是基于Netty 的響應(yīng)式開發(fā)模式。
?創(chuàng)建模塊
我們的Gatewa既然是負(fù)責(zé)網(wǎng)絡(luò)路由的,那么它首先肯定是個(gè)模塊,所以我們的第一步就是需要?jiǎng)?chuàng)建一個(gè)模塊。

修改該模塊的pom.xml文件,讓其繼承父模塊及導(dǎo)入相應(yīng)的依賴
<parent>
<groupId>org.example</groupId>
<artifactId>Cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.35</version>
</dependency>
</dependencies>因?yàn)樗械姆?wù)都要接入網(wǎng)關(guān),而服務(wù)都在注冊(cè)中心有記錄,所以我們網(wǎng)關(guān)要與Nacos關(guān)聯(lián),首先需要在配置文件中與Nacos做配置并且在啟動(dòng)類開啟Nacos
@EnableDiscoveryClient(啟動(dòng)類打上該注解)
server:
port: 8083
spring:
cloud:
nacos:
server-addr: localhost:8848
application:
name: geteway將全部服務(wù)啟動(dòng)就可以看到我們的gateway也被注冊(cè)到Nacos中啦

?使用Gateway的三種方式
??方法一
gateway:
discovery:
locator:
#是否與服務(wù)發(fā)現(xiàn)組件進(jìn)行結(jié)合,通過service-id(必須設(shè)置成大寫)轉(zhuǎn)發(fā)到具體的服務(wù)實(shí)例。默認(rèn) false
#為true代表開啟基于服務(wù)發(fā)現(xiàn)的路由規(guī)則。
enabled: true
#配置之后訪問時(shí)service-id無需大寫
lower-case-service-id: true
注意:我們的gateway是與spring下的nacos的標(biāo)簽同級(jí)別可不要將它寫在nacos下面


前面是通過服務(wù)直接訪問的,后面則是通過網(wǎng)關(guān)向服務(wù)發(fā)起的請(qǐng)求,此時(shí)我們的請(qǐng)求已經(jīng)被官網(wǎng)處理了。
??方法二
第二種方式是為了防止使用第一種方式的時(shí)候服務(wù)名字太長而導(dǎo)致的麻煩,這種方式類似于為服務(wù)名又起了一個(gè)別名。
gateway:
routes:
# 路由標(biāo)識(shí)(id:標(biāo)識(shí),具有唯一性)
- id: user-consumer-api
#目標(biāo)服務(wù)地址(uri:地址,請(qǐng)求轉(zhuǎn)發(fā)后的地址),會(huì)自動(dòng)從注冊(cè)中心獲得服務(wù)的IP,不需要手動(dòng)寫死
uri: lb://consume
#優(yōu)先級(jí),越小越優(yōu)先
predicates:
# 路徑匹配,
- Path=/aa/**
filters:
#前綴過濾,請(qǐng)求地址:http://localhost:8084/usr/hello
#此處配置去掉1個(gè)路徑前綴,再配置上面的 Path=/usr/**,就將**轉(zhuǎn)發(fā)到指定的微服務(wù)
- StripPrefix=1
這里如果使用的是http://localhost:8083/aa/test01就會(huì)映射到consume這個(gè)服務(wù),并且通過前綴過濾會(huì)過濾掉aa拿到test01就會(huì)映射到consume/test01上,得到如下結(jié)果????

??方法三
第三種方式是結(jié)合配置讀取類進(jìn)行的,我們將對(duì)服務(wù)的網(wǎng)關(guān)配置寫在Nacos,然后再用這個(gè)讀取類去進(jìn)行讀取,獲取我們想要的路由信息。
gateway:
nacos:
server-addr: ${spring.cloud.nacos.server-addr}
data-id: dynamic-routing.json
group: DEFAULT_GROUP首先需要新建一個(gè)POJO包將以下類進(jìn)行創(chuàng)建
package org.example.geteway.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author hgh
*/
@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class FilterEntity {
//過濾器對(duì)應(yīng)的Name
private String name;
//路由規(guī)則
private Map<String, String> args = new LinkedHashMap<>();
}package org.example.geteway.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ConfigurationProperties(prefix = "gateway.nacos")
@Component
public class GatewayNacosProperties {
private String serverAddr;
private String dataId;
private String namespace;
private String group;
}package org.example.geteway.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author hgh
*/
@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class PredicateEntity {
//斷言對(duì)應(yīng)的Name
private String name;
//斷言規(guī)則
private Map<String, String> args = new LinkedHashMap<>();
}package org.example.geteway.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.ArrayList;
import java.util.List;
/**
* @author hgh
*/
@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class RouteEntity {
//路由id
private String id;
//路由斷言集合
private List<PredicateEntity> predicates = new ArrayList<>();
//路由過濾器集合
private List<FilterEntity> filters = new ArrayList<>();
//路由轉(zhuǎn)發(fā)的目標(biāo)uri
private String uri;
//路由執(zhí)行的順序
private int order = 0;
}最后創(chuàng)建一個(gè)配置信息讀取類,這個(gè)類是一個(gè)基于 Spring Cloud Gateway 和 Nacos 的動(dòng)態(tài)路由配置類,它實(shí)現(xiàn)了一個(gè) Spring 提供的事件推送接口 ApplicationEventPublisherAware。它的功能主要包括監(jiān)聽 Nacos 的配置變化、解析從 Nacos 讀取的路由配置信息(json格式)、路由更新、以及組裝和定義路由信息等。通過這個(gè)類,可以實(shí)現(xiàn)路由信息的動(dòng)態(tài)管理和更新。
package org.example.geteway;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.example.geteway.pojo.FilterEntity;
import org.example.geteway.pojo.GatewayNacosProperties;
import org.example.geteway.pojo.PredicateEntity;
import org.example.geteway.pojo.RouteEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* 此類實(shí)現(xiàn)了Spring Cloud Gateway + nacos 的動(dòng)態(tài)路由,
* 它實(shí)現(xiàn)一個(gè)Spring提供的事件推送接口ApplicationEventPublisherAware
*/
@SuppressWarnings("all")
@Slf4j
@Component
public class DynamicRoutingConfig implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Autowired
private GatewayNacosProperties gatewayProperties;
@Autowired
private ObjectMapper mapper;
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* 這個(gè)方法主要負(fù)責(zé)監(jiān)聽Nacos的配置變化,這里先使用參數(shù)構(gòu)建一個(gè)ConfigService,
* 再使用ConfigService開啟一個(gè)監(jiān)聽,
* 并且在監(jiān)聽的方法中刷新路由信息。
*/
@Bean
public void refreshRouting() throws NacosException {
//創(chuàng)建Properties配置類
Properties properties = new Properties();
System.out.println(gatewayProperties);
//設(shè)置nacos的服務(wù)器地址,從配置類GatewayProperties中獲取
properties.put(PropertyKeyConst.SERVER_ADDR, gatewayProperties.getServerAddr());
//設(shè)置nacos的命名空間,表示從具體的命名空間中獲取配置信息,不填代表默認(rèn)從public獲得
if (gatewayProperties.getNamespace() != null) {
properties.put(PropertyKeyConst.NAMESPACE, gatewayProperties.getNamespace());
}
//根據(jù)Properties配置創(chuàng)建ConfigService類
ConfigService configService = NacosFactory.createConfigService(properties);
//獲得nacos中已有的路由配置
String json = configService.getConfig(gatewayProperties.getDataId(), gatewayProperties.getGroup(), 5000);
this.parseJson(json);
//添加監(jiān)聽器,監(jiān)聽nacos中的數(shù)據(jù)修改事件
configService.addListener(gatewayProperties.getDataId(), gatewayProperties.getGroup(), new Listener() {
@Override
public Executor getExecutor() {
return null;
}
/**
* 用于接收遠(yuǎn)端nacos中數(shù)據(jù)修改后的回調(diào)方法
*/
@Override
public void receiveConfigInfo(String configInfo) {
log.warn(configInfo);
//獲取nacos中修改的數(shù)據(jù)并進(jìn)行轉(zhuǎn)換
parseJson(configInfo);
}
});
}
/**
* 解析從nacos讀取的路由配置信息(json格式)
*/
public void parseJson(String json) {
log.warn("從Nacos返回的路由配置(JSON格式):" + json);
boolean refreshGatewayRoute = JSONObject.parseObject(json).getBoolean("refreshGatewayRoute");
if (refreshGatewayRoute) {
List<RouteEntity> list = JSON.parseArray(JSONObject.parseObject(json).getString("routeList")).toJavaList(RouteEntity.class);
for (RouteEntity route : list) {
update(assembleRouteDefinition(route));
}
} else {
log.warn("路由未發(fā)生變更");
}
}
/**
* 路由更新
*/
public void update(RouteDefinition routeDefinition) {
try {
this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
log.warn("路由刪除成功:" + routeDefinition.getId());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
try {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
log.warn("路由更新成功:" + routeDefinition.getId());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 路由定義
*/
public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {
RouteDefinition definition = new RouteDefinition();
// ID
definition.setId(routeEntity.getId());
// Predicates
List<PredicateDefinition> pdList = new ArrayList<>();
for (PredicateEntity predicateEntity : routeEntity.getPredicates()) {
PredicateDefinition predicateDefinition = new PredicateDefinition();
predicateDefinition.setArgs(predicateEntity.getArgs());
predicateDefinition.setName(predicateEntity.getName());
pdList.add(predicateDefinition);
}
definition.setPredicates(pdList);
// Filters
List<FilterDefinition> fdList = new ArrayList<>();
for (FilterEntity filterEntity : routeEntity.getFilters()) {
FilterDefinition filterDefinition = new FilterDefinition();
filterDefinition.setArgs(filterEntity.getArgs());
filterDefinition.setName(filterEntity.getName());
fdList.add(filterDefinition);
}
definition.setFilters(fdList);
// URI
URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
definition.setUri(uri);
return definition;
}
}現(xiàn)在需要我們?nèi)acos創(chuàng)建對(duì)應(yīng)的配置 dynamic-routing.json

{
"refreshGatewayRoute": true,
"routeList": [
{
"id": "consumer-api",
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/cum/**"
}
}
],
"filters": [
{
"name": "StripPrefix",
"args": {
"_genkey_0": "1"
}
}
],
"uri": "lb://consumer",
"order": 0
},
{
"id": "provider-api",
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/pvr/**"
}
}
],
"filters": [
{
"name": "StripPrefix",
"args": {
"_genkey_0": "1"
}
}
],
"uri": "lb://provider",
"order": 0
}
]
}現(xiàn)在我們就可以通過獲取Nacos所配置的路由進(jìn)行訪問了

如果你更改了Nacos的信息也會(huì)實(shí)時(shí)發(fā)送改變不用重啟服務(wù)器

到此這篇關(guān)于Spring Cloud Gateway組件的三種使用方式的文章就介紹到這了,更多相關(guān)Spring Cloud Gateway組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring Cloud Gateway層限流實(shí)現(xiàn)過程
- Spring Cloud Gateway內(nèi)置的斷言和過濾器作用說明
- Spring Cloud Gateway 緩存區(qū)異常問題及解決方案
- spring cloud gateway中redis一直打印重連日志問題及解決
- Spring?Cloud?Gateway?2.x跨域時(shí)出現(xiàn)重復(fù)Origin的BUG問題
- SpringCloud-Gateway網(wǎng)關(guān)的使用實(shí)例教程
- 使用SpringCloud Gateway解決跨域問題
- 一文掌握spring cloud gateway(總結(jié)篇)
相關(guān)文章
Ribbon負(fù)載均衡服務(wù)調(diào)用的示例詳解
Rbbo其實(shí)就是一個(gè)軟負(fù)載均衡的客戶端組件,他可以和其他所需請(qǐng)求的客戶端結(jié)合使用,這篇文章主要介紹了Ribbon負(fù)載均衡服務(wù)調(diào)用案例代碼,需要的朋友可以參考下2023-01-01
Java數(shù)據(jù)結(jié)構(gòu)之HashMap源碼深入分析
Java HashMap是一種基于哈希表實(shí)現(xiàn)的鍵值對(duì)存儲(chǔ)結(jié)構(gòu),可以實(shí)現(xiàn)快速的數(shù)據(jù)查找和存儲(chǔ)。它是線程不安全的,但在單線程環(huán)境中運(yùn)行效率高,被廣泛應(yīng)用于Java開發(fā)中2023-04-04
淺談Java序列化和反序列化為何要實(shí)現(xiàn)Serializable接口
這篇文章主要介紹了淺談Java序列化和反序列化為何要實(shí)現(xiàn)Serializable接口,序列化最重要的作用是在傳遞和保存對(duì)象時(shí).保證對(duì)象的完整性和可傳遞性,對(duì)象轉(zhuǎn)換為有序字節(jié)流,以便在網(wǎng)絡(luò)上傳輸或者保存在本地文件中,需要的朋友可以參考下2023-12-12
Spring-基于Spring使用自定義注解及Aspect實(shí)現(xiàn)數(shù)據(jù)庫切換操作
這篇文章主要介紹了Spring-基于Spring使用自定義注解及Aspect實(shí)現(xiàn)數(shù)據(jù)庫切換操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
VS?Code中運(yùn)行Java?SpringBoot的項(xiàng)目詳細(xì)步驟
這篇文章主要介紹了VS?Code中運(yùn)行Java?SpringBoot項(xiàng)目的相關(guān)資料,文中涵蓋了安裝必要的擴(kuò)展、配置環(huán)境、創(chuàng)建或?qū)腠?xiàng)目、配置調(diào)試環(huán)境、運(yùn)行和調(diào)試項(xiàng)目、使用Spring?Boot?Actuator以及配置任務(wù)自動(dòng)化等步驟,需要的朋友可以參考下2024-12-12
java 實(shí)現(xiàn)將Object類型轉(zhuǎn)換為int類型
這篇文章主要介紹了java 實(shí)現(xiàn)將Object類型轉(zhuǎn)換為int類型的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
詳談Java中net.sf.json包關(guān)于JSON與對(duì)象互轉(zhuǎn)的坑
下面小編就為大家分享一篇Java中net.sf.json包關(guān)于JSON與對(duì)象互轉(zhuǎn)的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助2017-12-12
詳解eclipse創(chuàng)建maven項(xiàng)目實(shí)現(xiàn)動(dòng)態(tài)web工程完整示例
這篇文章主要介紹了詳解eclipse創(chuàng)建maven項(xiàng)目實(shí)現(xiàn)動(dòng)態(tài)web工程完整示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12

