Learn about the Spring Cloud Gateway

The Spring Cloud Gateway is an API Gateway based on Spring 5, Project Reactor, and Spring Boot 2. It is one of the major components of the Spring Cloud microservice ecosystem. The Spring Cloud Gateway is mainly responsible for routing distribution of interface requests, and supports extended operations such as security verification of requests, traffic monitoring and traffic control. It is also worth noting that the Spring Cloud Gateway uses a non-blocking I/O model by default to distribute request routes. In terms of processing some I/O time-consuming requests, compared with other synchronous blocking I/O model written in Java, the gateway performance is higher, the number of concurrent processing is also higher, avoiding I/O blocking (network calls, database operations, etc.) resulting in idle threads, which can continue to process and respond to other requests.

Application scenario of the Spring Cloud Gateway

As an API Gateway, Spring Cloud Gateway also provides powerful capabilities, including integrated support for load balancing, dynamic routing, access control, current limiting fuses, and buried point monitoring. If the existing microservice system is based on the Java ecosystem or even the Spring ecosystem, then it is very suitable to use the Spring Cloud Gateway as the API application Gateway, so that the aggregation management of multiple microservice apis, external unified output.

In keeping with the Spring family tradition, the Spring Cloud Gateway is also designed to provide a simple and efficient way to extend API routing and request concerns for developers already familiar with Spring or Spring Boot. The Spring Cloud Gateway is inexpensive to learn and easy to use and extend by taking advantage of features such as annotation-driven and automated configuration of the underlying framework.

Get started with Spring Cloud Gateway quickly

You can quickly build an API Gateway using the Spring Cloud Gateway, but before you do that, let’s introduce some of the specific concepts involved in using the Spring Cloud Gateway framework to deepen your understanding of the Spring Cloud Gateway. Convenient for later use.

  • Routing: The basic component of the Spring Cloud Gateway, usually consisting of an ID, target URI, and a series of predicates and filters.
  • Predicate: This is the Java 8 libraryPredicateObject of the typePredicate<ServerWebExchange>Is used to match HTTP request data information, such as request header information and request body information. If the assertion for a request is true, the route it is associated with is considered a match and the request is sent to the route for processing.
  • Filters: components used to modify the request or response of a route. In Spring Cloud Gateway, the GatewayFilter interface is implemented and constructed by the GatewayFilterFactor-based concrete implementation class.

With these three concepts in mind, you can see how Spring Cloud Gateway handles client requests, which is a great help in making use of Spring Cloud Gateway.

  • The client request is first obtained by GatewayHandlerMapping, and then the corresponding route is found based on the assertion match
  • After the route is found, the processing method of the associated set of request filters is completed, the request is sent to the corresponding service program of the target URI, and the service response is obtained.
  • After receiving the response, the gateway passes the processing method of the associated response filter, and the GatewayHandlerMapping also returns the response to the client.

It should also be noted that Spring Cloud Gateway filters are executed in order, and the order of execution is determined by the size of the order value. The smaller the value, the higher the priority, the earlier the execution.

How to implement API aggregation

Now that we know how Spring Cloud Gateway handles requests as a whole, let’s quickly build an API Gateway based on Spring Cloud Gateway and see what we need to pay attention to in practice. It should be noted that the Spring Cloud Gateway used in this article belongs to the latest milestone version 2.2.3, corresponding to Spring Boot version 2.3.1, and the Spring Cloud version is Hoxton.sr6. Using Spring Initializr, a project spring-Cloud-gateway-Quick-start was quickly created after selecting the corresponding version and dependency. In order to realize the routing of the request and show the effect of the gateway, Create userservice application demo-userservice and orderservice application demo-orderservice respectively, and provide a callable API interface respectively.

User services exposed port 8071, providing /user/get interfaces:

// Demo-userService project @restController@requestMapping ("/user") Public class UserServiceController { @RequestMapping("/get") public User get() { return User.mock(); }}Copy the code

Similarly, the order service exposes port 8061 and provides /order/ GET interfaces:

// Demo-OrderService project @restController@requestMapping ("/order") public class OrderServiceController { @RequestMapping("/get") public Order get() { return Order.mock(); }}Copy the code

Next, we will aggregate the two service interfaces in the Spring-Cloud-gateway-Quick-start project through the Spring Cloud Gateway. First, we will take a look at the implementation using the Spring Cloud Gateway API:

@SpringBootApplication public class DemogatewayApplication { public static void main(String[] args) { SpringApplication.run(DemogatewayApplication.class, args); } @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes().route("user-service", r -> r.path("/user/*").uri("http://localhost:8071")) .route("order-service", r -> r.path("/order/*").uri("http://localhost:8061")) .build(); }}Copy the code

Next, we will aggregate the two service interfaces in the Spring-Cloud-gateway-Quick-start project through the Spring Cloud Gateway. First, we will take a look at the implementation using the Spring Cloud Gateway API:

Spring-cloud-gateway-quick-start and other service applications can be used to access the user service and order service through the gateway application.

one@192 ~ % curl http://localhost:8080/user/get
{"id":4720186416534735290,"token":"86b6118d-7dc6-4d30-a5f3-3d5fc6348f9a"}

one@192 ~ % curl http://localhost:8080/order/get
{"id":5832646761962425508,"title":"My Order"}Copy the code

Back to the API implementation code, the DemogatewayApplication#customRouteLocator method defines two routes with ids user-service and order-service, and sets the assertion to match the request. And the actual destination request address. The assertion of the route here adopts the rule of path matching. As long as the original request address meets the corresponding rule, the route will be matched. However, Spring Cloud Gate also supports rich assertion rules, such as host matching, request body field matching, request data matching and so on, which are enough to meet the rule of custom route assertion.

Since using an API is hard coding the routing rules into the program, this is not scalable or maintainable. Therefore, another implementation method is recommended: configuration. Let’s look at how to configure the same functionality in application.properties:

spring.cloud.gateway.routes[0].id=order-service
spring.cloud.gateway.routes[0].uri=http://localhost:8061
spring.cloud.gateway.routes[0].predicates[0].name=Path
spring.cloud.gateway.routes[0].predicates[0].args[pattern]=/order/*
spring.cloud.gateway.routes[1].id=user-service
spring.cloud.gateway.routes[1].uri=http://localhost:8071
spring.cloud.gateway.routes[1].predicates[0].name=Path
spring.cloud.gateway.routes[1].predicates[0].args[pattern]=/user/*Copy the code

Restarting the gateway application using the preceding configuration can also achieve the effect of the PREVIOUS API method. Because the routing rules are transferred to the configuration file, API management is greatly convenient, and dynamic routing is also possible. Of course, dynamic routing needs to be implemented. In addition to routing configuration, additional extension is also needed to realize dynamic refreshing of routing rules, which involves more advanced usage of Spring Cloud Gateway. This article will not be described in detail, but can wait for subsequent advanced use and analysis of the article or refer to other implementation materials on the Internet.

How do I customize filters

To handle requests or responses from the API, the Spring Cloud Gateway provides a filter component to do this and has a lot of built-in power. In addition, there are two types of filters: global filter and gateway filter. For global filter, all requests matching routes are processed by global filter. The gateway filter takes effect only when displayed on the specified route.

The Spring Cloud Gateway defaults to eight global filters:

  • ForwardRoutingFilter
  • LoadBalancerClientFilter (deprecated)
  • ReactiveLoadBalancerClientFilter
  • WebClientHttpRoutingFilter
  • NettyWriteResponseFilter
  • RouteToRequestUrlFilter
  • WebsocketRoutingFilter
  • GatewayMetricsFilter

And gateway filter even more, and by corresponding factory class to construct, such as for fusing HystrixGatewayFilterFactory, RequestRateLimiterGatewayFilterFactory for current limiting, Used to modify the request data ModifyRequestBodyGatewayFilterFactory and so on, of course, also support the developers to define your own filter.

First let’s look at how to customize a global filter, the code implementation is relatively simple:

@Component public class CustomGlobalFilter implements GlobalFilter, Ordered { private Logger log = LoggerFactory.getLogger(MyAuthFilterFactory.class); @override public <Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info(" Execute custom filter "); return chain.filter(exchange); } @Override public int getOrder() { return -1; }}Copy the code

This allows you to add a global filter for all routes. Different from the global filter definition, gateway filter must be declared on the specified route to take effect, referring to the official built-in gateway interceptor, customize a simple gateway interceptor factory for authorization as follows:

@Component public class MyAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<MyAuthGatewayFilterFactory.Config> { private Logger logger = LoggerFactory.getLogger(MyAuthGatewayFilterFactory.class); public MyAuthGatewayFilterFactory() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return new GatewayFilter() { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); MultiValueMap<String, String> queryParams = request.getQueryParams(); String from = queryParams.getFirst(config.getAuthKey()); ServerHttpResponse response = exchange.getResponse(); Logger.warn (" Verification authorization begins "); If (config.getauthValue ().equals(from)) {logger.warn(" Verify authorization succeeded "); return chain.filter(exchange); } else {logger.warn(" Failed to verify authorization "); response.setStatusCode(HttpStatus.OK); response.getHeaders().setContentType(MediaType.valueOf("text/html; charset=utf-8")); DataBuffer wrap = response.bufferFactory().wrap(config.getAuthFailMsg().getBytes(Charset.forName("UTF-8"))); return response.writeWith(Flux.just(wrap)); }}}; } public static class Config { private String authKey = "from"; private String authValue = "system"; Private String authFailMsg = "authFailMsg "; public String getAuthKey() { return authKey; } public void setAuthKey(String authKey) { this.authKey = authKey; } public String getAuthValue() { return authValue; } public void setAuthValue(String authValue) { this.authValue = authValue; } public String getAuthFailMsg() { return authFailMsg; } public void setAuthFailMsg(String authFailMsg) { this.authFailMsg = authFailMsg; }}}Copy the code

To use it under user-service routing, add the following configuration to the application.properties configuration file:

spring.cloud.gateway.routes[1].filters[0].name=MyAuthCopy the code

Here is the name of the need to MyAuthGatewayFilterFactory class MyAuth consistent, Spring Cloud Gateway automatically AuthGatewayFilterFactory on joining together to find the corresponding Gateway filter, If not found, the startup fails and an exception is thrown:

java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name MyAuth2Copy the code

Configuration to restart application gateway, it is to use the original way to request the user service, has been unable to normal visit, will only return to check authorization failure information, must start with http://localhost:8080/user/get? From =system access to obtain data successfully, indicating that the defined authorization interceptor has worked.

Here we have customised both the global interceptor and the gateway interceptor, which we usually extend on the gateway interceptor and use with built-in filters. Finally, upload the complete implementation code to Gitlab: github.com/wrcj12138aa… , interested friends can also refer to.

This article is published by OpenWrite!