Hello,大家好,我是 V 哥。最近寫到 使用 Nacos 實現動態路由的問題,整理了一下思路和案例,分享給大家。
使用 Nacos 實現 Spring Cloud Gateway 的動態路由,主要涉及到以下幾個步驟:
- 添加依賴:在 Spring Cloud Gateway 應用的
pom.xml文件中添加 Nacos 相關依賴。 - 配置 Nacos:在
application.yml或application.properties文件中配置 Nacos 服務地址。 - 啓用動態路由:在配置文件中啓用 Nacos 動態路由功能。
- 創建動態路由配置:在 Nacos 配置中心創建動態路由的配置信息。
- 監聽配置變化:在 Spring Cloud Gateway 應用中監聽 Nacos 配置變化,動態更新路由規則。
下面是具體的實現步驟和代碼案例,來看一下:
1. 添加依賴
在 pom.xml 文件中添加 Spring Cloud Gateway 和 Nacos 相關依賴:
<dependencies>
<!-- Spring Cloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Spring Cloud Alibaba Nacos Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Spring Cloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
2. 配置 Nacos
在 application.yml 文件中配置 Nacos 服務地址:
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服務地址
config:
server-addr: 127.0.0.1:8848 # Nacos 配置中心地址
file-extension: yml # 配置文件格式
group: DEFAULT_GROUP # 配置分組
namespace: # 配置命名空間
3. 啓用動態路由
在 application.yml 文件中啓用 Nacos 動態路由功能:
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 開啓從註冊中心動態創建路由的功能
lower-case-service-id: true # 使用小寫服務名,默認是大寫
4. 創建動態路由配置
在 Nacos 配置中心創建一個配置文件,例如 gateway-routes.yml,內容如下:
spring:
cloud:
gateway:
routes:
- id: my-service-route
uri: lb://MY-SERVICE
predicates:
- Path=/my-service/**
filters:
- StripPrefix=1
5. 監聽配置變化
在 Spring Cloud Gateway 應用中,創建一個配置類來監聽 Nacos 配置變化,並刷新路由規則:
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class DynamicRouteService {
private final RouteDefinitionWriter routeDefinitionWriter;
private final RouteDefinitionLocator routeDefinitionLocator;
public DynamicRouteService(RouteDefinitionWriter routeDefinitionWriter,
RouteDefinitionLocator routeDefinitionLocator) {
this.routeDefinitionWriter = routeDefinitionWriter;
this.routeDefinitionLocator = routeDefinitionLocator;
}
@EventListener
public void onEnvironmentChange(EnvironmentChangeEvent event) {
if (event.getKeys().contains("spring.cloud.gateway.routes")) {
routeDefinitionLocator.getRouteDefinitions()
.subscribe(routeDefinitions -> {
routeDefinitionWriter.delete("*").subscribe();
routeDefinitionWriter.save(routeDefinitions).subscribe();
});
}
}
}
這個類會監聽環境變化事件,當檢測到 spring.cloud.gateway.routes 配置項發生變化時,會重新加載和刷新路由規則。
我們通過使用 Nacos 實現 Spring Cloud Gateway 的動態路由。通過在 Nacos 配置中心維護路由配置,可以實現不重啓網關服務的情況下動態更新路由規則,這對於微服務架構中的服務治理非常有用。
在使用 Nacos 動態路由時,如果服務下線了,Spring Cloud Gateway 會如何響應?
當使用 Nacos 動態路由時,如果服務下線,Spring Cloud Gateway 會通過 Nacos 的服務發現機制感知到這一變化,並根據配置的動態路由規則進行調整。如何配置 Spring Cloud Gateway 以響應服務下線的情況呢?來,上代碼:
首先,確保咱們的項目中已經添加了 Spring Cloud Gateway 和 Spring Cloud Alibaba Nacos Discovery 的依賴。
1. application.yml 配置
在 application.yml 中配置 Nacos 服務發現和動態路由:
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服務地址
gateway:
routes:
- id: my-service-route
uri: lb://MY-SERVICE
predicates:
- Path=/my-service/**
filters:
- StripPrefix=1
discovery:
locator:
enabled: true
lower-case-service-id: true
2. Nacos 配置中心的動態路由配置
在 Nacos 配置中心創建一個名為 gateway-routes.json 的配置文件,內容如下:
{
"spring": {
"cloud": {
"gateway": {
"routes": [
{
"id": "my-service-route",
"uri": "lb://MY-SERVICE",
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/my-service/**"
}
}
],
"filters": [
{
"name": "StripPrefix",
"args": {
"_genkey_1": "1"
}
}
]
}
]
}
}
}
}
3. 動態路由配置監聽
創建一個配置類來監聽 Nacos 配置變化,並刷新路由規則:
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.route.RoutesRefreshedEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import java.util.Properties as JavaProperties;
@Component
public class NacosDynamicRoute implements ApplicationRunner {
@Autowired
private RouteDefinitionRepository routeDefinitionRepository;
@Autowired
private ApplicationEventPublisher publisher;
private ConfigService configService;
public NacosDynamicRoute(NacosConfigProperties properties) throws NacosException {
JavaProperties javaProperties = new JavaProperties();
javaProperties.setProperty("serverAddr", properties.getServerAddr());
javaProperties.setProperty("namespace", properties.getNamespace());
configService = NacosFactory.createConfigService(javaProperties);
}
@Override
public void run(ApplicationArguments args) {
try {
String routeJson = configService.getConfig("gateway-routes.json", "DEFAULT_GROUP", 5000);
refreshRoutes(routeJson);
configService.addListener("gateway-routes.json", "DEFAULT_GROUP", s -> refreshRoutes(s));
} catch (NacosException e) {
e.printStackTrace();
}
}
private void refreshRoutes(String routeJson) {
SpringCloudRouteDefinition routeDefinition = JsonUtils.deserialize(routeJson, SpringCloudRouteDefinition.class);
routeDefinitionRepository.delete("*").subscribe();
routeDefinitionRepository.save(routeDefinition.getRouteDefinitions()).subscribe();
publisher.publishEvent(new RoutesRefreshedEvent(this));
}
// 內部類,用於反序列化 Nacos 配置
static class SpringCloudRouteDefinition {
private RouteDefinition[] routeDefinitions;
// getter 和 setter 省略
}
}
NacosDynamicRoute 類會在應用啓動時從 Nacos 配置中心加載路由配置,並註冊一個監聽器來監聽配置變化。當配置發生變化時,它會重新加載路由配置並刷新路由規則。點贊+關注,學習 Java 不迷路。