spring cloud 2.x version of the dynamic routing Gateway Tutorial

Summary

As employed herein Spring cloud 2.1.8RELEASE, version = Greenwich.SR3

Achieve in front of several Spring cloud Gateway Based on the article. reference

Foreword

After writing several articles about Spring Cloud Gateway discovery, knowledge Gateway is overly broad, really profound experience of the "Spring cloud into a deep sea."

Real production environment, using Spring Cloud Gateway is used as the entrance to all traffic, in order to ensure high availability of the system, try to avoid reboot the system, it is necessary to Spring Dynamic routing Cloud Gateway to handle. Previous article " Gateway Routing Gateway Guide " provides routing configuration, system startup time, routing configuration and rules will be loaded into memory, you can not do without restarting the service can dynamically add, modify, delete routing memory configuration and rules.

Simple dynamic routing to achieve

Spring Cloud Gateway provides the source code to modify the GatewayControllerEndpoint class routing configuration, but does not seem to official documents detailed instructions for use, simply introduce a few simple api interface. Junior partner interested can first view the official documentation ( Section 11 API Actuator ).

Causing the official document:

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.

1.1 add relevant pom-dependent

Increase the spring-boot-starter-actuator based on the original dependent on the spring-gateway

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
复制代码

1.2 application.yml disposed in the increase

management:
  endpoints:
    web:
      exposure:
        include: "*"
复制代码

Configuration Description: management.endpoints.web.exposure.include expose all gateway endpoints

1.3 Starting Services

Start the service, visit http: // localhost: 8100 / actuator / gateway / routes, which are routes we can see all the information.

We can also access a single routing information: HTTP: // localhost: 8100 / Actuator / Gateway / routes / CompositeDiscoveryClient_EUREKA-CLIENT

It is shown below:

1.4 add, modify routing information

Gateway is used by default GatewayControllerEndpoint this class, GatewayControllerEndpoint also inherited the AbstractGatewayControllerEndpoint class.

:( methods provided with only a few columns related methods, other methods of guy who can view their own source code)

  1. / Gateway / routes to query all routes
  2. / Gateway / routes / {id} in accordance with the routing information query single id
  3. / Gateway / routes / {id} @PostMapping a new route
  4. / Gateway / routes / {id} @DeleteMapping delete a route

1.4.1 New Route

We The routing information / gateway / routes returned to simulate a request parameter @PostMapping

{
    "uri": "http://httpbin.org:80",
    "predicates": [
        {
            "args": {
                "pattern": "/ribbon/**"
            },
            "name": "Path"
        }
    ],
    "filters": []
}
复制代码

This is the post request may be sent by a postman, as shown:

return 1 response has been inserted prove successful, we can http: // localhost: 8100 / actuator / gateway / routes / view route information, display the results as follows:

Screenshot red box information is newly added

1.4.2 delete routing information

We can directly use simulation DeleteMapping postman request, HTTP: // localhost: 8100 / Actuator / Gateway / routes / addroutes

It is shown below:

This time we visit http: // localhost: 8100 / actuator / gateway / routes, you can see the newly added routes have been deleted successful.

1.5 Summary

Based on Spring Cloud Gateway default dynamic routing method implemented I'm done, I have already mentioned in the introduction, this approach is based on the realization jvm memory, once the service is restarted, the new routing configuration information is completely gone. All this time we can consider the possibility of such reference GatewayControllerEndpoint to achieve their own set of dynamic routing method, and then the routing information persistence.

Custom dynamic routing

1.1 Definitions related classes

1.1.1 custom entity classes

You can customize the entity class, here I stole a lazy, the direct use of the Gateway of RouteDefinition class, interested partners can refer to a small class RouteDefinition own extension, and then write a Convert class to convert into a custom class RouteDefinition it.

1.1.2 Custom RedisRouteDefinitionRepository class

I am here as the persistence layer using redis routing configuration information, so write a 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 Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> 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<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(routeDefinition -> {
            redisUtils.hset(KEY, routeDefinition.getId(), JsonUtils.toString(routeDefinition));
            return Mono.empty();
        });
    }

    /**
     * 删除
     * @param routeId
     * @return
     */
    @Override
    public Mono<Void> delete(Mono<String> 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)));
        });
    }
}

复制代码

1.1.3 Custom Controller and Service

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;

/**
 * 自定义动态路由
 * @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<ResponseEntity<Object>> 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<ResponseEntity<Object>> 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;
    }
}

复制代码

1.2 application.yml

application.yml configure all endpoints to storm drain Gateway, you can see the configuration information prior to the test.

1.3 Starting Services

Start Spring cloud Gateway service, first visit http: // localhost: 8100 / actuator / gateway / routes, view existing routing configuration information. We then add method postman request, HTTP: // localhost: 8100 / Gateway / add, if shown:

Note that the contents of the red box in the screenshot. Proof has been added successfully.

Then we visit http: // localhost: 8100 / actuator / gateway / routes to see the results. If you like this:

Similarly we can access update and delete methods that I described here is not too much.

to sum up

Custom dynamic routing core principle is necessary to rewrite the gateway module, which is RedisRouteDefinitionRepository class mentioned earlier. I'm not lazy here to redefine the corresponding entity class, to note here that the format of the incoming parameters must be configured in accordance with application.yml, and then turn into json, if the format is incorrect error.

Code address

gitHub address


"Srping Cloud 2.X white tutorial" directory

  • Writing is not easy, please indicate the source, like a small number of partners can focus the public like to see more articles.
  • Contact: [email protected]

Guess you like

Origin juejin.im/post/5dbee3dde51d456e652839ea