本篇內(nèi)容主要講解“如何配置spring cloud 2.x版本Gateway動態(tài)路由”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“如何配置spring cloud 2.x版本Gateway動態(tài)路由”吧!
我們提供的服務(wù)有:成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、普寧ssl等。為成百上千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的普寧網(wǎng)站制作公司
本文采用的Spring cloud為2.1.8RELEASE,version=Greenwich.SR3
寫了幾篇關(guān)于Spring Cloud Gateway的文章后發(fā)現(xiàn),Gateway涉及的知識范圍太廣了,真是深刻體會了“一入Spring cloud深似?!?。
現(xiàn)實生產(chǎn)環(huán)境中,使用Spring Cloud Gateway都是作為所有流量的入口,為了保證系統(tǒng)的高可用,盡量避免系統(tǒng)的重啟,所以需要Spring Cloud Gateway的動態(tài)路由來處理。之前的文章《Gateway路由網(wǎng)關(guān)教程》提供的路由配置,在系統(tǒng)啟動時候,會將路由配置和規(guī)則加載到內(nèi)存當(dāng)中,無法做到不重啟服務(wù)就可以動態(tài)的新增、修改、刪除內(nèi)存中的路由配置和規(guī)則。
Spring Cloud Gateway源碼中提供了GatewayControllerEndpoint類來修改路由配置,但是官方文檔好像并沒有做詳細的使用說明,只是簡單介紹了幾個簡單的api接口。感興趣的小伙伴可以先查看官方文檔(第11章節(jié) Actuator API)。
引致官方文檔:
The
/gateway
actuator endpoint allows to monitor and interact with a Spring Cloud Gateway application. To be remotely accessible, the endpoint has to be enabled and exposed via HTTP or JMX in the application properties.
在原來spring-gateway的基礎(chǔ)上增加spring-boot-starter-actuator依賴
org.springframework.boot spring-boot-starter-actuator
management: endpoints: web: exposure: include: "*"
配置說明:management.endpoints.web.exposure.include 暴露所有的gateway端點
啟動服務(wù),訪問http://localhost:8100/actuator/gateway/routes,這是我們可以看到所有的routes信息。 image-20191102225203034.png 我們也可以訪問單個路由信息:http://localhost:8100/actuator/gateway/routes/CompositeDiscoveryClient_EUREKA-CLIENT
顯示如下:image-20191102225853005.png
Gateway默認使用的是GatewayControllerEndpoint這個類,GatewayControllerEndpoint又繼承了AbstractGatewayControllerEndpoint類。
提供的方法:(只列具了幾個相關(guān)方法,其他方法小伙們可以自行查看源碼)
/gateway/routes 查詢所有路由信息
/gateway/routes/{id} 根據(jù)路由id查詢單個信息
/gateway/routes/{id} @PostMapping 新增一個路由信息
/gateway/routes/{id} @DeleteMapping 刪除一個路由信息
我們可根據(jù)/gateway/routes返回的路由信息,來模仿一個@PostMapping請求參數(shù)
{ "uri": "http://httpbin.org:80", "predicates": [ { "args": { "pattern": "/ribbon/**" }, "name": "Path" } ], "filters": [] }
這是我們可以通過postman來發(fā)送一個post請求,如圖所示:
response返回1證明已經(jīng)插入成功,我們可以通過http://localhost:8100/actuator/gateway/routes/查看路由信息,顯示結(jié)果如下:
截圖紅框中的信息就是新增加的
我們可以直接用postman模擬DeleteMapping請求,http://localhost:8100/actuator/gateway/routes/addroutes
顯示如下:
這時候我們在訪問http://localhost:8100/actuator/gateway/routes,可以看到新增加的路由已經(jīng)被刪除成功了。
基于Spring Cloud Gateway默認方法實現(xiàn)的動態(tài)路由我就完成了,在前言中我已經(jīng)提到了,這種方式是基于jvm內(nèi)存實現(xiàn),一旦服務(wù)重啟,新增的路由配置信息就是完全消失了。所有這個時候我們可以考慮是否可以參考GatewayControllerEndpoint這類,自己實現(xiàn)一套動態(tài)路由方法,然后將路由信息持久化。
可以自定義實體類,我這里偷了一個懶,直接用了Gateway的RouteDefinition類,感興趣的小伙伴可以參考RouteDefinition類自己擴展,然后寫一個Convert類將自定義的類轉(zhuǎn)換成RouteDefinition就可以了。
我這邊采用redis做為路由配置的信息的持久層,所以寫了一個RedisRouteDefinitionRepository。
package spring.cloud.demo.spring.gateway.component; import com.google.common.collect.Lists; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionRepository; import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import spring.cloud.demo.spring.gateway.redis.RedisUtils; import spring.cloud.demo.spring.gateway.util.JsonUtils; import javax.annotation.Resource; import java.util.List; /** * @auther: maomao * @DateT: 2019-11-03 */ @Component public class RedisRouteDefinitionRepository implements RouteDefinitionRepository { //存儲的的key private final static String KEY = "gateway_dynamic_route"; @Resource private RedisUtils redisUtils; /** * 獲取路由信息 * @return */ @Override public FluxgetRouteDefinitions() { List gatewayRouteEntityList = Lists.newArrayList(); redisUtils.hgets(KEY).stream().forEach(route -> { RouteDefinition result = JsonUtils.parseJson(route.toString(), RouteDefinition.class); gatewayRouteEntityList.add(result); }); return Flux.fromIterable(gatewayRouteEntityList); } /** * 新增 * @param route * @return */ @Override public Mono save(Mono route) { return route.flatMap(routeDefinition -> { redisUtils.hset(KEY, routeDefinition.getId(), JsonUtils.toString(routeDefinition)); return Mono.empty(); }); } /** * 刪除 * @param routeId * @return */ @Override public Mono delete(Mono routeId) { return routeId.flatMap(id -> { if (redisUtils.hHashKey(KEY, id)) { redisUtils.hdel(KEY, id); return Mono.empty(); } return Mono.defer(() -> Mono.error(new NotFoundException("route definition is not found, routeId:" + routeId))); }); } }
package spring.cloud.demo.spring.gateway.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; import spring.cloud.demo.spring.gateway.service.GatewayDynamicRouteService; import javax.annotation.Resource; /** * 自定義動態(tài)路由 * @auther: maomao * @DateT: 2019-11-03 */ @RestController @RequestMapping("/gateway") @Slf4j public class GatewayDynamicRouteController { @Resource private GatewayDynamicRouteService gatewayDynamicRouteService; @PostMapping("/add") public String create(@RequestBody RouteDefinition entity) { int result = gatewayDynamicRouteService.add(entity); return String.valueOf(result); } @PostMapping("/update") public String update(@RequestBody RouteDefinition entity) { int result = gatewayDynamicRouteService.update(entity); return String.valueOf(result); } @DeleteMapping("/delete/{id}") public Mono> delete(@PathVariable String id) { return gatewayDynamicRouteService.delete(id); } }
package spring.cloud.demo.spring.gateway.service; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; import spring.cloud.demo.spring.gateway.component.RedisRouteDefinitionRepository; import javax.annotation.Resource; /** * @auther: maomao * @DateT: 2019-11-03 */ @Service public class GatewayDynamicRouteService implements ApplicationEventPublisherAware { @Resource private RedisRouteDefinitionRepository redisRouteDefinitionRepository; private ApplicationEventPublisher applicationEventPublisher; /** * 增加路由 * @param routeDefinition * @return */ public int add(RouteDefinition routeDefinition) { redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe(); applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)); return 1; } /** * 更新 * @param routeDefinition * @return */ public int update(RouteDefinition routeDefinition) { redisRouteDefinitionRepository.delete(Mono.just(routeDefinition.getId())); redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe(); applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)); return 1; } /** * 刪除 * @param id * @return */ public Mono> delete(String id) { return redisRouteDefinitionRepository.delete(Mono.just(id)).then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build()))) .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build())); } @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } }
application.yml配置要暴漏Gateway的所有端點,可以看考之前的配置信息。
啟動Spring cloud Gateway服務(wù),先訪問http://localhost:8100/actuator/gateway/routes,查看已有的路由配置信息。然后我們用postman請求add方法,http://localhost:8100/gateway/add,如果所示:
注意截圖中紅框的內(nèi)容。證明已經(jīng)新增成功。
這時我們在訪問http://localhost:8100/actuator/gateway/routes查看結(jié)果。如果所示:
同理我們可以訪問update和delete方法,我這里就不過多描述了。
自定義動態(tài)路由核心原理其實就要重寫網(wǎng)關(guān)模塊,也就是之前提到的RedisRouteDefinitionRepository類。我這里偷懶沒有重新定義對應(yīng)的實體類,這里需要注意的是,傳入?yún)?shù)一定要按照application.yml中配置的格式,然后轉(zhuǎn)成json,如果格式不正確會報錯。
gitHub地址
spring cloud 2.x版本 Eureka Server服務(wù)注冊中心教程
spring cloud 2.x版本 Eureka Client服務(wù)提供者教程
spring cloud 2.x版本 Ribbon服務(wù)發(fā)現(xiàn)教程(內(nèi)含集成Hystrix熔斷機制)
spring cloud 2.x版本 Feign服務(wù)發(fā)現(xiàn)教程(內(nèi)含集成Hystrix熔斷機制)
spring cloud 2.x版本 Zuul路由網(wǎng)關(guān)教程
spring cloud 2.x版本 config分布式配置中心教程
spring cloud 2.x版本 Hystrix Dashboard斷路器教程
spring cloud 2.x版本 Gateway路由網(wǎng)關(guān)教程
spring cloud 2.x版本 Gateway自定義過濾器教程
spring cloud 2.x版本 Gateway熔斷、限流教程
spring cloud 2.x版本 Gateway動態(tài)路由教程
到此,相信大家對“如何配置spring cloud 2.x版本Gateway動態(tài)路由”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!