Spring Cloud Gateway + Nacos 實(shí)現(xiàn)動(dòng)態(tài)路由
本節(jié)開(kāi)始介紹 SpringCloud Gateway 中動(dòng)態(tài)路由的實(shí)現(xiàn)方法,包括:
Nacos 集成動(dòng)態(tài)路由配置,更新配置文件即自動(dòng)更新路由
MySQL + 二級(jí)緩存實(shí)現(xiàn),主要基于 Gateway 的一些特性進(jìn)行重寫(xiě),實(shí)現(xiàn)路由信息的自動(dòng)更新
這篇文章主要介紹第一種方式:將配置文件放到 Nacos 進(jìn)行托管,網(wǎng)關(guān)服務(wù)通過(guò)引入 Nacos 而自動(dòng)更新路由配置信息。實(shí)現(xiàn)較為簡(jiǎn)單。
本節(jié)代碼在:https://github.com/laolunsi/spring-boot-examples,參考例 23 即可。
下面進(jìn)入正題。
1. 創(chuàng)建網(wǎng)關(guān)服務(wù)
創(chuàng)建一個(gè) springboot gateway 網(wǎng)關(guān)服務(wù),默認(rèn)是從 yaml 文件中讀取 route 的配置。如果想要從 nacos 中讀取配置,就要引入 nacos-config 的依賴(lài),并設(shè)置配置文件的地址。
首先創(chuàng)建一個(gè)空 maven 項(xiàng)目 spring-cloud-gateway-nacos-routes ,聲明 springboot 和 springcloud 的版本,并引入 nacos。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.eknown</groupId>
<artifactId>spring-cloud-gateway-nacos-routes</artifactId>
<description>SpringCloud Gateway Nacos 動(dòng)態(tài)路由示例</description>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.9.0.RELEASE</version>
</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>
然后創(chuàng)建一個(gè) springboot 項(xiàng)目,命名為:gateway-demo ,引入 gateway/nacos-config 等依賴(lài):
<parent> <groupId>com.eknown</groupId> <artifactId>spring-cloud-gateway-nacos-routes</artifactId> <version>1.0-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <artifactId>gateway-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>gateway-demo</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-core --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-core</artifactId> <version>5.3.9</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-alibaba-nacos-config</artifactId> <version>0.9.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> </dependencies>
我們知道 SpringBoot 加載配置文件的順序是:bootstrap.yml -> application.yml 這里需要將 nacos-config 的配置項(xiàng)放到 bootstrap.yml 中,這樣項(xiàng)目啟動(dòng)時(shí)才能優(yōu)先從 nacos 中加載配置信息。主要配置如下:
server:
port: 8501
spring:
application:
name: gateway-demo
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
group: ${gateway.dynamicRoute.group}
file-extension: json
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true
redis:
host: localhost
password:
port: 6379
database: 10
# 自定義的配置項(xiàng),用于設(shè)置路由信息所載的配置文件,比如這里是 group + dataId
gateway:
dynamicRoute:
enabled: true
dataType: nacos
dataId: 'yq_routes'
group: 'YQ_GATEWAY'
將自定義配置項(xiàng)加載到 Java 中:
@Configuration
public class GatewayConfig {
public static String NACOS_DATA_ID;
public static String NACOS_GROUP_ID;
@Value("${gateway.dynamicRoute.dataId}")
public void setNacosDataId(String dataId) {
NACOS_DATA_ID = dataId;
}
@Value("${gateway.dynamicRoute.group}")
public void setNacosGroupId(String group) {
NACOS_GROUP_ID = group;
}
}
下面我們重寫(xiě)一下 RouteDefinitionRepository 接口,將其改造成使用 Nacos 引入路由配置信息就可以了!
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {
private static final Logger log = LoggerFactory.getLogger(NacosRouteDefinitionRepository.class);
// 更新路由信息需要的
private ApplicationEventPublisher publisher;
// nacos 的配置信息
private NacosConfigProperties nacosConfigProperties;
// 構(gòu)造器
public NacosRouteDefinitionRepository(ApplicationEventPublisher publisher, NacosConfigProperties nacosConfigProperties) {
this.publisher = publisher;
this.nacosConfigProperties = nacosConfigProperties;
System.out.println(GatewayConfig.NACOS_DATA_ID + ", " + GatewayConfig.NACOS_GROUP_ID);
addListener();
}
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
try {
String content = nacosConfigProperties.configServiceInstance()
.getConfig(GatewayConfig.NACOS_DATA_ID, GatewayConfig.NACOS_GROUP_ID,5000);
List<RouteDefinition> routeDefinitions = getListByStr(content);
return Flux.fromIterable(routeDefinitions);
} catch (NacosException e) {
log.error("getRouteDefinitions by nacos error", e);
}
return Flux.fromIterable(CollUtil.newArrayList());
}
/**
* 添加Nacos監(jiān)聽(tīng)
*/
private void addListener() {
try {
nacosConfigProperties.configServiceInstance().addListener(GatewayConfig.NACOS_DATA_ID, GatewayConfig.NACOS_GROUP_ID, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
log.info("自動(dòng)更新配置...\r\n" + configInfo);
publisher.publishEvent(new RefreshRoutesEvent(this));
}
});
} catch (NacosException e) {
log.error("nacos-addListener-error", e);
}
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return null;
}
@Override
public Mono<Void> delete(Mono<String> routeId) {
return null;
}
// 從 json 中解析出路由配置信息 —— 所以配置文件的格式一定要寫(xiě)對(duì)!
private List<RouteDefinition> getListByStr(String content) {
if (StrUtil.isNotEmpty(content)) {
return JSONObject.parseArray(content, RouteDefinition.class);
}
return new ArrayList<>(0);
}
}
最簡(jiǎn)單的方法是直接將這個(gè) NacosRouteDefinitionRepository 類(lèi)聲明為 Bean。這里為了方便配置的切換寫(xiě)的復(fù)雜一點(diǎn),通過(guò) DynamicRouteConfig 來(lái)確認(rèn)是否需要引入 nacos 的配置:
/**
* 動(dòng)態(tài)路由配置
*/
@Configuration
@ConditionalOnProperty(prefix = "gateway.dynamicRoute", name = "enabled", havingValue = "true")
public class DynamicRouteConfig {
@Autowired
private ApplicationEventPublisher publisher;
/**
* Nacos實(shí)現(xiàn)方式
*/
@Configuration
@ConditionalOnProperty(prefix = "gateway.dynamicRoute", name = "dataType", havingValue = "nacos", matchIfMissing = true)
public class NacosDynRoute {
@Autowired
private NacosConfigProperties nacosConfigProperties;
@Bean
public NacosRouteDefinitionRepository nacosRouteDefinitionRepository() {
return new NacosRouteDefinitionRepository(publisher, nacosConfigProperties);
}
}
}
到這一步我們其實(shí)已經(jīng)基本完成了 gateway + nacos 動(dòng)態(tài)網(wǎng)關(guān)的實(shí)現(xiàn)了。下面我們測(cè)試一下。
2. 測(cè)試
創(chuàng)建一個(gè)簡(jiǎn)單的 springboot web 項(xiàng)目,引入 nacos 作為注冊(cè)中心,并實(shí)現(xiàn)一個(gè)接口,比如:
server: port: 8502 spring: application: name: demo cloud: nacos: discovery: server-addr: 127.0.0.1:8848
注:這里實(shí)際上不需要引入 nacos 作為注冊(cè)中心的,因?yàn)槁酚蓪?shí)際上就是一個(gè)轉(zhuǎn)發(fā)功能,這個(gè)轉(zhuǎn)發(fā)操作是由 gateway 提供的,而不是 nacos 提供的。。。
接口:
@RestController
@RequestMapping(value = "test")
public class TestAction {
@GetMapping(value = "hello")
public String hello(String name) {
System.out.println("hello, " + name);
return "hello, " + name;
}
}
啟動(dòng) nacos,添加配置文件,需要設(shè)置配置文件的 group 和 dataId 與上面的 gateway.dynamicRoute 中的配置相同。
內(nèi)容示例:
[
{
"id": "demo",
"uri": "lb://demo",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/api/demo/**"
}
}
],
"filters": [
{
"name": "StripPrefix",
"args": {
"parts": "2"
}
}
]
}
]
啟動(dòng) gateway-demo 以及 demo 項(xiàng)目,訪問(wèn) gateway-demo 項(xiàng)目對(duì)應(yīng)的路由地址,比如這里的:http://localhost:8501/api/demo/test/hello,如果運(yùn)行正常,請(qǐng)求將被轉(zhuǎn)發(fā)到 demo 項(xiàng)目的 /test/hello 接口,并返回對(duì)應(yīng)的數(shù)據(jù)。
今天的分享就到這里啦!本來(lái)打算寫(xiě)一篇前文所說(shuō)的第二種實(shí)現(xiàn)方法的文章的,不過(guò)由于二級(jí)緩存那邊是用了組里封裝的框架所以不便公布,后面有空我會(huì)自己實(shí)現(xiàn)一個(gè)基本的 demo,并同步到 Git 上!
水平有限,如有紕漏還請(qǐng)見(jiàn)諒。如果對(duì)文章內(nèi)容有什么疑問(wèn),可以留言或直接聯(lián)系我!thanks for your reading !
以上就是Spring Cloud Gateway + Nacos 實(shí)現(xiàn)動(dòng)態(tài)路由的詳細(xì)內(nèi)容,更多關(guān)于SpringCloud Gateway 動(dòng)態(tài)路由實(shí)現(xiàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JAVA設(shè)計(jì)模式之建造者模式原理與用法詳解
這篇文章主要介紹了JAVA設(shè)計(jì)模式之建造者模式,簡(jiǎn)單說(shuō)明了建造者模式的原理、組成,并結(jié)合實(shí)例形式分析了java建造者模式的定義與用法,需要的朋友可以參考下2017-08-08
Springboot教程之如何設(shè)置springboot熱重啟
這篇文章主要介紹了Springboot教程之如何設(shè)置springboot熱重啟,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
SpringBoot整合MyBatis-Plus3.1教程詳解
這篇文章主要介紹了SpringBoot整合MyBatis-Plus3.1詳細(xì)教程,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08
解決在IDEA下使用JUnit的問(wèn)題(解決過(guò)程)
很多朋友跟小編反饋在IDEA下使用JUnit進(jìn)行實(shí)例測(cè)試的時(shí)候出現(xiàn)很多奇葩問(wèn)題,今天小編通過(guò)本文給大家分享idea使用JUnit出現(xiàn)問(wèn)題及解決過(guò)程,感興趣的朋友跟隨小編一起看看吧2021-05-05

