Table of contents
Three, Gateway core architecture
Built-in route assertion factory
Custom Route Assertion Factory
1. Gateway Introduction
Everyone knows that in the microservice architecture, a system will be split into many microservices. So how to call so many microservices as a client? If there is no gateway, we can only record the address of each microservice on the client side, and then call them separately.
The more popular gateways in the industry include the following:
Ngnix+lua uses nginx's reverse proxy and load balancing to achieve load balancing and high availability for api servers. Lua is a scripting language that can be used to write some simple logic. nginx supports lua scripts
Kong is developed based on Nginx+Lua, has high performance and stability, and has multiple available plug-ins (current limiting, authentication, etc.) that can be used out of the box. Problem: Only supports Http protocol; secondary development, free expansion is difficult; management API is provided, and there is a lack of easier-to-use control and configuration methods.
Zuul Netflix 's open source gateway has rich functions and is developed using JAVA, which is easy for secondary development Problems: lack of control and cannot be dynamically configured; there are many dependent components; processing Http requests depends on the web container, and its performance is not as good as Nginx
The gateway service developed by Spring Cloud Gateway to replace Zuul will be introduced in detail below.
2. Introduction to Gateway
Spring Cloud Gateway is a gateway developed by Spring based on technologies such as Spring 5.0, Spring Boot 2.0 and Project Reactor. It aims to provide a simple and effective unified API routing management method for microservice architecture. Its goal is to replace Netflix Zuul, which not only provides a unified routing method, but also provides the basic functions of the gateway based on the Filter chain, such as: security, monitoring and current limiting.
advantage:
Strong performance: 1.6 times that of the first-generation gateway Zuul
Powerful functions: built-in many practical functions, such as forwarding, monitoring, current limiting , etc.
Elegant design, easy to expand
shortcoming:
Its implementation relies on Netty and WebFlux, not the traditional Servlet programming model, and the learning cost is high
It cannot be deployed in Servlet containers such as Tomcat and Jetty, but can only be executed as a jar package
Requires Spring Boot 2.0 and above to support
Gateway Quick Start
Requirement: Access the api gateway through the browser, and then forward the request to the commodity microservice through the gateway (there are three versions shown below)
basic version
Step 1: Create a new module and import related dependencies
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Spring-Cloud</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api-gateway</artifactId>
<dependencies>
<!--gateway 注意 此模式不能引入starter-web -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
</dependencies>
</project>
Add annotation @EnableDiscoveryClient to the main class
package com.dengxuyan.apigateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
Step 3: Add configuration files
server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: product_route
uri: lb://shop-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
predicates:
- Path=/product-serv/**
filters:
- StripPrefix=1
- id: product_route
uri: lb://shop-order # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
predicates:
- Path=/order-serv/**
filters:
- StripPrefix=1
Test effect
Access address of commodity microservice without gateway: http://localhost:8080/product/get/1
Access address via gateway product microservice: http://localhost:7000/product-serv/product/get/1
Step 4: Start the project and access the microservice through the gateway
Enhanced Edition
Now write the address of the forwarding path hard in the configuration file. We have analyzed the problems caused by the hard writing of the address before. Next, we get this address from the registration center.
Change the yml file on the basis of the basic version
server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: product_route
uri: lb://shop-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
predicates:
- Path=/product-serv/**
filters:
- StripPrefix=1
Test effect: You can randomly access an instance in the commodity microservice
background printing
abbreviated version
It is also possible to change the yml file on the original basis
Remove the configuration about routing
server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 让gateway可以发现nacos中的微服务
Start the project and access the microservice through the gateway
At this time, I found that as long as I access according to the format of gateway address/microservice/interface, I can get a successful response.
Replenish:
Cross-domain request: At this time, it is found that as long as the access is made according to the format of gateway address/microservice/interface, a successful response can be obtained.
spring:
cloud:
gateway:
# 跨域
globalcors:
corsConfigurations:
'[/**]':
allowedHeaders: "*"
allowedOrigins: "*"
allowedMethods: "*"
Notes:
allowedHeaders: header allowed fields
allowedOrigins: allowed origins
allowedMethods: allow request method
Three, Gateway core architecture
Route (Route) is one of the most basic components in gateway, which represents a specific routing information carrier. The following information is mainly defined:
id, route identifier, different from other Routes.
uri, the destination uri pointed to by the route, that is, the microservice to which the client request is finally forwarded.
order, used for sorting among multiple Routes, the smaller the value, the higher the sorting, and the higher the matching priority.
predicate, the function of the assertion is to make conditional judgments, and only when the assertion returns true, the routing will be actually executed.
filter, the filter is used to modify the request and response information.
Implementation process
The execution process is roughly as follows:
Gateway Client sends a request to Gateway Server
The request will first be extracted by the HttpWebHandlerAdapter and assembled into a gateway context
Then the context of the gateway is passed to DispatcherHandler, which is responsible for dispatching the request to RoutePredicateHandlerMapping
RoutePredicateHandlerMapping is responsible for route lookup, and judges whether the route is available according to the route assertion
If the assertion is successful, the filter chain is created by FilteringWebHandler and called
The request will go through the PreFilter--microservice--PostFilter method once, and finally return the response
Four, assert
Predicate (assertion, predicate) is used for conditional judgment, only when the assertion returns true, the routing will be executed. Assertion means: under what conditions can routing and forwarding be carried out
Built-in route assertion factory
Spring Cloud Gateway includes a number of built-in assertion factories, all of which match against different attributes of HTTP requests.
You can go to the official website to view related documents: Spring | Home
About the configuration file of the built-in route assertion project
server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 让gateway可以发现nacos中的微服务
routes:
- id: product_route
uri: lb://shop-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
predicates: #添加了触发路由的条件
- Path=/product-serv/**
- Query=name,zk.
- Method=POST #限制请求方式为POST
filters:
- StripPrefix=1
It is necessary to meet the three conditions of the assertion at the same time so that no error will be reported
The parameter values and parameter names in the figure should correspond to those in the yml configuration file
Custom Route Assertion Factory
Let's set up a scenario: Suppose our application only allows people whose age is between (min, max) to visit.
Step 1: In the configuration file, add an Age assertion configuration
server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 让gateway可以发现nacos中的微服务
routes:
- id: product_route
uri: lb://shop-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
predicates:
- Path=/product-serv/**
- Age=18,60
filters:
- StripPrefix=1
Step 2: Customize an assertion factory and implement the assertion method
package com.dengxuyan.apigateway.predicates;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
//这是一个自定义的路由断言工厂类,要求有两个
//1 名字必须是 配置+RoutePredicateFactory
//2 必须继承AbstractRoutePredicateFactory<配置类>
@Component
public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
public AgeRoutePredicateFactory() {
super(AgeRoutePredicateFactory.Config.class);
}
//用于从配置文件中获取参数值赋值到配置类中的属性上
@Override
public List<String> shortcutFieldOrder() {
//这里的顺序要跟配置文件中的参数顺序一致
return Arrays.asList("minAge", "maxAge");
}
//断言
@Override
public Predicate<ServerWebExchange> apply(AgeRoutePredicateFactory.Config
config) {
return new Predicate<ServerWebExchange>() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
//从serverWebExchange获取传入的参数
String ageStr =
serverWebExchange.getRequest().getQueryParams().getFirst("age");
if (StringUtils.isNotEmpty(ageStr)) {
int age = Integer.parseInt(ageStr);
return age > config.getMinAge() && age < config.getMaxAge();
}
else{
return false;
}
// return true;
}
};
}
//配置类,用于接收配置文件中的对应参数
@Data
@NoArgsConstructor
public static class Config {
private int minAge;//18
private int maxAge;//60
}
}
Test results:
#The test found that when age is at (20,60), it can be accessed, and other ranges cannot access
http://localhost:7000/product-serv/product/1?age=40
http://localhost:7000/product-serv/product /1?age=10