Spring Gateway整合nacos實現動態路由配置

本文主要介紹Spring Gateway透過整合nacos實現路由動態配置,達到不重啟API閘道器實現動態暴露內部微服務介面的目的。主要流程如下:

一、建立Maven專案test-gateway, pom檔案如下:

4。0。0 com。test。gateway test-gateway 1。0。0 UTF-8 UTF-8 1。8 Hoxton。SR8 2。2。3。RELEASE 1。2。73 2。3。2。RELEASE org。springframework。cloud spring-cloud-starter-gateway com。alibaba。cloud spring-cloud-starter-alibaba-nacos-config com。alibaba。cloud spring-cloud-starter-alibaba-nacos-discovery <!—— sentinel提供的gataway介面卡 ——> com。alibaba。cloud spring-cloud-alibaba-sentinel-gateway <!——sentinel依賴包 ——> com。alibaba。cloud spring-cloud-starter-alibaba-sentinel com。alibaba。csp sentinel-datasource-nacos <!—— 對外暴露 Spring Boot 監控指標 ——> org。springframework。boot spring-boot-starter-actuator org。springframework。boot spring-boot-starter-test test org。junit。vintage junit-vintage-engine com。alibaba fastjson ${fastjson。version} org。projectlombok lombok true org。springframework。cloud spring-cloud-dependencies ${spring。cloud。version} pom import com。alibaba。cloud spring-cloud-alibaba-dependencies ${alibaba。cloud。version} pom import <!—— Import dependency management from Spring Boot ——> org。springframework。boot spring-boot-dependencies ${spring。boot。version} pom import test-gateway org。springframework。boot spring-boot-maven-plugin org。codehaus。mojo versions-maven-plugin false org。apache。maven。plugins maven-compiler-plugin 8 8

二、建立啟動類Apllication.java,內容如下:

package com。test。gateway;import org。springframework。boot。SpringApplication;import org。springframework。boot。autoconfigure。SpringBootApplication;import org。springframework。cloud。client。discovery。EnableDiscoveryClient;import org。springframework。context。annotation。ComponentScan;@EnableDiscoveryClient@SpringBootApplication@ComponentScan(basePackages = { “com。test。gateway”})public class GatewayApplication { public static void main(String[] args) { System。setProperty(“csp。sentinel。app。type”, “1”); SpringApplication。run(GatewayApplication。class, args); }}

三、建立閘道器呼叫nacos配置類GatewayConfig.java

package com。test。gateway。config;import org。springframework。beans。factory。annotation。Value;import org。springframework。context。annotation。Configuration;@Configurationpublic class GatewayConfig { public static final long DEFAULT_TIMEOUT = 30000; public static String NACOS_SERVER_ADDR; public static String NACOS_NAMESPACE; public static String NACOS_ROUTE_DATA_ID; public static String NACOS_ROUTE_GROUP; @Value(“${spring。cloud。nacos。discovery。server-addr}”) public void setNacosServerAddr(String nacosServerAddr) { NACOS_SERVER_ADDR = nacosServerAddr; } @Value(“${spring。cloud。nacos。discovery。namespace}”) public void setNacosNamespace(String nacosNamespace) { NACOS_NAMESPACE = nacosNamespace; } @Value(“${nacos。gateway。route。config。data-id}”) public void setNacosRouteDataId(String nacosRouteDataId) { NACOS_ROUTE_DATA_ID = nacosRouteDataId; } @Value(“${nacos。gateway。route。config。group}”) public void setNacosRouteGroup(String nacosRouteGroup) { NACOS_ROUTE_GROUP = nacosRouteGroup; }}

四、建立動態路由管理服務

1、建立動態路管理類DynamicRouteServiceImpl。java

package com。test。gateway。config;import org。springframework。beans。factory。annotation。Autowired;import org。springframework。cloud。gateway。event。RefreshRoutesEvent;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。stereotype。Service;import lombok。extern。slf4j。Slf4j;import reactor。core。publisher。Mono;/** * 動態更新路由閘道器service * 1)實現一個Spring提供的事宜推送介面ApplicationEventPublisherAware * 2)提供動態路由的基礎方式,可透過獲取bean操作該類的方式。該類提供新增路由、更新路由、刪除路由,然後實現公佈的功效。 */@Slf4j@Servicepublic class DynamicRouteServiceImpl implements ApplicationEventPublisherAware { @Autowired private RouteDefinitionWriter routeDefinitionWriter; /** * 公佈事宜 */ @Autowired private ApplicationEventPublisher publisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this。publisher = applicationEventPublisher; } /** * 刪除路由 * @param id * @return */ public String delete(String id) { try { log。info(“gateway delete route id {}”,id); this。routeDefinitionWriter。delete(Mono。just(id)); return “delete success”; } catch (Exception e) { return “delete fail”; } } /** * 更新路由 * @param definition * @return */ public String update(RouteDefinition definition) { try { log。info(“gateway update route {}”,definition); this。routeDefinitionWriter。delete(Mono。just(definition。getId())); } catch (Exception e) { return “update fail,not find route routeId: ”+definition。getId(); } try { routeDefinitionWriter。save(Mono。just(definition))。subscribe(); this。publisher。publishEvent(new RefreshRoutesEvent(this)); return “success”; } catch (Exception e) { return “update route fail”; } } /** * 增添路由 * @param definition * @return */ public String add(RouteDefinition definition) { log。info(“gateway add route {}”,definition); routeDefinitionWriter。save(Mono。just(definition))。subscribe(); this。publisher。publishEvent(new RefreshRoutesEvent(this)); return “success”; }}

2、建立透過nacos對路由動態管理類DynamicRouteServiceImplByNacos。java

package com。test。gateway。config;import java。util。List;import java。util。Properties;import java。util。concurrent。Executor;import javax。annotation。PostConstruct;import org。springframework。beans。factory。annotation。Autowired;import org。springframework。cloud。gateway。route。RouteDefinition;import org。springframework。context。annotation。DependsOn;import org。springframework。stereotype。Component;import com。alibaba。fastjson。JSON;import com。alibaba。nacos。api。NacosFactory;import com。alibaba。nacos。api。config。ConfigService;import com。alibaba。nacos。api。config。listener。Listener;import com。alibaba。nacos。api。exception。NacosException;import lombok。extern。slf4j。Slf4j;/** * * 透過nacos下發動態路由設定,監聽Nacos中gateway-route設定 * */@Component@Slf4j@DependsOn({ “gatewayConfig” }) // 依賴於gatewayConfig beanpublic class DynamicRouteServiceImplByNacos { @Autowired private DynamicRouteServiceImpl dynamicRouteService; private ConfigService configService; @PostConstruct public void init() { log。info(“gateway route init。。。”); try { configService = initConfigService(); if (configService == null) { log。warn(“initConfigService fail”); return; } String configInfo = configService。getConfig(GatewayConfig。NACOS_ROUTE_DATA_ID, GatewayConfig。NACOS_ROUTE_GROUP, GatewayConfig。DEFAULT_TIMEOUT); log。info(“獲取閘道器當前設定:\r\n{}”, configInfo); List definitionList = JSON。parseArray(configInfo, RouteDefinition。class); for (RouteDefinition definition : definitionList) { log。info(“update route : {}”, definition。toString()); dynamicRouteService。add(definition); } } catch (Exception e) { log。error(“初始化閘道器路由時發生錯誤”, e); } dynamicRouteByNacosListener(GatewayConfig。NACOS_ROUTE_DATA_ID, GatewayConfig。NACOS_ROUTE_GROUP); } /** * 監聽Nacos下發的動態路由設定 * * @param dataId * @param group */ public void dynamicRouteByNacosListener(String dataId, String group) { try { configService。addListener(dataId, group, new Listener() { @Override public void receiveConfigInfo(String configInfo) { log。info(“舉行閘道器更新:\n\r{}”, configInfo); List definitionList = JSON。parseArray(configInfo, RouteDefinition。class); for (RouteDefinition definition : definitionList) { log。info(“update route : {}”, definition。toString()); dynamicRouteService。update(definition); } } @Override public Executor getExecutor() { log。info(“getExecutor\n\r”); return null; } }); } catch (NacosException e) { log。error(“從nacos吸收動態路由設定失足!!!”, e); } } /** * 初始化閘道器路由 nacos config * * @return */ private ConfigService initConfigService() { try { Properties properties = new Properties(); properties。setProperty(“serverAddr”, GatewayConfig。NACOS_SERVER_ADDR); properties。setProperty(“namespace”, GatewayConfig。NACOS_NAMESPACE); return configService = NacosFactory。createConfigService(properties); } catch (Exception e) { log。error(“初始化閘道器路由時發生錯誤”, e); return null; } } }

五、建立閘道器服務配置檔案bootstrap.yml

server: port: 80spring: profiles: active: dev application: name: test-gateway cloud: nacos: config: namespace: ${spring。profiles。active} server-addr: http://127。0。0。1:8848 extension-configs[0]: data-id: test_gateway_commons。yml group: DEFAULT_GROUP refresh: true#nacos dynamic router confignacos: gateway: route: config: data-id: gateway_dynamic_router group: DEFAULT_GROUP

1、test_gateway_commons。yml配置檔案內容下:

#sentinel 相關配置spring: cloud: sentinel: transport: dashboard: http://127。0。0。1。2:8080 port: 8719 scg: fallback: mode: response response-status: 455 response-body: error! nacos: discovery: namespace: dev server-addr: 127。0。0。1:8848management: endpoints: web: exposure: include: ‘*’

2、JSON路由配置檔案gateway_dynamic_router的內容如下:

[{ “id”: “order-router”, “order”: 0, “predicates”: [{ “args”: { “pattern”: “/orders/**” }, “name”: “Path” }], “uri”: “lb://order-service”},{ “id”: “user-router”, “order”: 2, “predicates”: [{ “args”: { “pattern”: “/users/**” }, “name”: “Path” }], “filters”:[ { “name”:“StripPrefix”, “args”:{“_genkey_0”:1} } ], “uri”: “lb://test-user-service”}]

透過以上步驟就實現了Spring Gateway整合nacos實現路由動態配置的功能。以後只要修改gateway_dynamic_router 檔案就可以實現服務的微服務的介面暴露和下線功能。

demo程式碼地址如下:https://gitee。com/sharepublicly/test-gateway