天天看點

spring-cloud-gateway(2)--->spring-cloud-gateway如何實作動态路由

1、什麼是動态路由,也就是在網關服務不停機的狀态下,動态的添加route或者删除route,這就是動态路由的定義,我們在前面實戰zuul的時候也提到過這個問題,當時的實作動态路由的方式是,使用配置中心進行route的配置,然後在增删路由的時候,使用actuator進行手動重新整理。 當然在 spring-cloud-gateway中也可以這樣實作,但是 spring-cloud-gateway中還為我們提供了另一種方式,那就是直接使用actuator API,官網位址如下:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#actuator-api。

2、使用 spring-cloud-gateway 的 actuator API來實作動态路由實戰:

      2.1、在項目中引入spring-boot-starter-actuator的依賴:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
           

       2.2、暴露端點:

management:
  endpoints:
    web:
      exposure:
        include: "*"
           

        2.3、使用 spring-cloud-gateway 的 actuator API來檢視已經配置的路由資訊,位址為 http://網關服務ip:網關服務位址/actuator/gateway/routes   可得出已經配置的路由清單:

[
    {
        "predicate": "Paths: [/gateway-server/**], match trailing slash: true",
        "metadata": {
            "jmx.port": "62460",
            "management.port": "6060"
        },
        "route_id": "ReactiveCompositeDiscoveryClient_GATEWAY-SERVER",
        "filters": [
            "[[RewritePath /gateway-server/(?<remaining>.*) = '/${remaining}'], order = 1]"
        ],
        "uri": "lb://GATEWAY-SERVER",
        "order": 0
    },
    {
        "predicate": "Paths: [/orderapi/**], match trailing slash: true",
        "route_id": "orderapi",
        "filters": [
            "[[StripPrefix parts = 1], order = 1]",
            "[[Hystrix name = 'fallbackcmd', fallback = forward:/orderapi/order/mock], order = 2]",
            "[org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory$$Lambda$878/[email protected], order = 3]"
        ],
        "uri": "http://localhost:7070",
        "order": 0
    },
    {
        "predicate": "Paths: [/userapi/**], match trailing slash: true",
        "route_id": "userapi",
        "filters": [
            "[[StripPrefix parts = 1], order = 1]"
        ],
        "uri": "lb://user-service",
        "order": 0
    },
    {
        "predicate": "(Paths: [/customer/predicate/**], match trailing slash: true && [email protected])",
        "route_id": "costomer_predicate",
        "filters": [
            "[[StripPrefix parts = 2], order = 1]"
        ],
        "uri": "http://www.baidu.com:80",
        "order": 0
    }
]
           

         2.4、使用 spring-cloud-gateway 的 actuator API來添加路由:

                 請求位址:http://localhost:6060/actuator/gateway/routes/api_route

                 請求方式:post   application/json

                 入參格式:

{
	"id": "first_route",
	"predicates": [{
		"name": "Path",
		"args": {
			"_genkey_0": "/api1"
		}
	}],
	"filters": [{
		"name": "StripPrefix",
		"args": {
			"_genkey_0": 1
		}
	}],
	"uri": "https://www.baidu.com",
	"order": 0
}
           

           添加完成後再次檢視路由清單,如下:

[
    {
        "predicate": "Paths: [/gateway-server/**], match trailing slash: true",
        "metadata": {
            "jmx.port": "62818",
            "management.port": "6060"
        },
        "route_id": "ReactiveCompositeDiscoveryClient_GATEWAY-SERVER",
        "filters": [
            "[[RewritePath /gateway-server/(?<remaining>.*) = '/${remaining}'], order = 1]"
        ],
        "uri": "lb://GATEWAY-SERVER",
        "order": 0
    },
    {
        "predicate": "Paths: [/orderapi/**], match trailing slash: true",
        "route_id": "orderapi",
        "filters": [
            "[[StripPrefix parts = 1], order = 1]",
            "[[Hystrix name = 'fallbackcmd', fallback = forward:http://localhost:6060/fallback], order = 2]",
            "[org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory$$Lambda$878/[email protected], order = 3]"
        ],
        "uri": "http://localhost:7070",
        "order": 0
    },
    {
        "predicate": "Paths: [/userapi/**], match trailing slash: true",
        "route_id": "userapi",
        "filters": [
            "[[StripPrefix parts = 1], order = 1]"
        ],
        "uri": "lb://user-service",
        "order": 0
    },
    {
        "predicate": "(Paths: [/customer/predicate/**], match trailing slash: true && [email protected])",
        "route_id": "costomer_predicate",
        "filters": [
            "[[StripPrefix parts = 2], order = 1]"
        ],
        "uri": "http://www.baidu.com:80",
        "order": 0
    },
    {
        "predicate": "Paths: [/api1], match trailing slash: true",
        "route_id": "api_route",
        "filters": [
            "[[StripPrefix parts = 1], order = 1]"
        ],
        "uri": "https://www.baidu.com:443",
        "order": 0
    }
]
           

               可見我們添加的路由api_route已經添加進去了,其他的删除的接口也都有。

3、spring-cloud-gateway 的 actuator API來實作動态route的擴充:

      上面我們講解了使用 actuator API來實作動态路由的實戰,接下來我們來針對這種方式進行擴充,為什麼要擴充呢?原因就是actuator API來實作動态路的方式,在預設情況下是沒有之持久化的,也就是說一旦重新開機網關服務的話,動态添加的路由就沒有了,是以我們需要進行擴充。

       我們就實作使用redis來儲存路由資訊吧,實作方式如下,在spring-cloud-gateway中提供了一個接口 RouteDefinitionRepository 路由定義倉庫,類圖如下:

spring-cloud-gateway(2)--->spring-cloud-gateway如何實作動态路由

            預設值提供了存在在記憶體中的倉庫。

        接下來我們來實作存儲在redis中的實作類:

@Component
public class RedisRouteDefRepository implements RouteDefinitionRepository {

    public static final String GATEWAY_ROUTE_REDIS_KEY = "gateway_route_redis_key";
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {

        List<RouteDefinition> list = new ArrayList <>();
        redisTemplate.opsForHash().values(GATEWAY_ROUTE_REDIS_KEY).stream().forEach(route->{
            list.add(JSON.parseObject(route.toString(), RouteDefinition.class));
        });

        return Flux.fromIterable(list);
    }

    @Override
    public Mono<Void> save(Mono <RouteDefinition> route) {

       return route.flatMap(routeDefinition ->{
            redisTemplate.opsForHash().put(GATEWAY_ROUTE_REDIS_KEY, routeDefinition.getId(), JSON.toJSONString(routeDefinition));
            return Mono.empty();
        });
    }

    @Override
    public Mono <Void> delete(Mono <String> routeId) {

        return routeId.flatMap(id->{
            redisTemplate.opsForHash().delete(GATEWAY_ROUTE_REDIS_KEY, id);
            return Mono.empty();
        });
    }
}
           

         這樣動态添加的路由資訊就會被儲存在redis中,而在配置檔案中定義的路由資訊是不會儲存在redis中的:

spring-cloud-gateway(2)--->spring-cloud-gateway如何實作動态路由

繼續閱讀