Welcome to my GitHub
Here is a classification and summary of all original (including supporting source code): 1618c5d0b9c3fb https://github.com/zq2599/blog_demos
About the "Spring Cloud Gateway Actual Combat" series
"Spring Cloud Gateway Actual Combat" is Xinchen's original series in the Java field. It aims to learn and master Spring Cloud Gateway with everyone through actual project combat, so as to better serve actual projects.
Overview of this article
As the beginning of "Spring Cloud Gateway Actual Combat", the main content of this article is as follows:
- Introduction to Basic Knowledge
- Confirm the version of the tools and services involved in the environment
- Start nacos as the registration center and configuration center for follow-up actual combat
- Create a maven parent project to manage the subsequent actual code and dependent library version
- Create a subproject named <font color="blue">common</font> to store common constants and data structures
- Create a web application named <font color="blue">provider-hello</font> for the target of gateway routing
- Run a simple demo to complete the first experience of spring-cloud-gateway
About Spring Cloud Gateway
- This is an API gateway built on the Spring technology stack, involving: Spring5, Spring Boot 2, Reactor, etc. The goal is to provide simple and efficient API routing for the project, as well as powerful expansion capabilities: security, monitoring, elastic computing, etc.
- The official architecture diagram is as follows. It can be seen that after the request arrives, <font color="blue">Handler Mapping</font> determines the real target corresponding to the request, and then gives it to the <font color="blue">Web Handler</font>, Chain processing is performed by a series of filters. From the red arrows and comments, you can find that there are filters running before and after the request:
Version Information
- The software and library version information involved in the "Spring Cloud Gateway Actual Combat" series is as follows:
- The main versions involved in the actual combat in this article are as follows:
- JDK:1.8.0_291
- IDEA:2021.1.3 (Ultimate Edition)
- maven:3.8.1
- Operating system: win10 64 bit
- springboot:2.4.2
- spring-cloud:2020.0.1
- spring-cloud-alibaba:2021.1
- For more detailed version matching relationship, please refer to: https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98 %8E
Core concepts in classic configuration
- Let’s first understand a few core concepts through a typical simplified version of the configuration. Assuming that the Spring Cloud Gateway application is running and listening on port 8080, once a remote request comes to port 8080, the following configuration will take effect. The three core concepts, and For the role of each configuration, please refer to the Chinese note:
spring:
cloud:
gateway:
# 核心概念1:路由,一个路由代表一个处理逻辑,
# 该逻辑里面包含三个元素:匹配条件(是否该此路由处理)、真实处理地址、过滤器
routes:
# id要确保唯一性
- id: add_request_header_route
# 真实处理地址,请求一旦确定是当前路由处理,就会转发到这个地址去
uri: https://example.org
# 核心概念2:谓语或者断言,作用是判断请求是否由当前路由处理
predicates:
# 这是断言的一种,检查请求的Cookie中mycookie的值是否等于mycookievalue
- Cookie=mycookie,mycookievalue
# 核心概念3:过滤器,请求前和请求后都可以有过滤器处理请求响应数据
filters:
# 这个过滤器的作用是在请求header中添加一个键值对,值等于"aaabbbccc"
- AddRequestHeader=X-Request-Red, aaabbbccc
- The predicates in the above configuration information is a simplified version of the configuration. The effect of comparing with the complete configuration is as follows. Simply put, one line is split into three items: name, args.name, args.regexp
- The theoretical knowledge is up, let’s get started as soon as possible
Start nacos-2.0.3
- Throughout the "pring Cloud Gateway actual combat" series, we will involve multiple services, which inevitably will use the registry and configuration center. Here I choose nacos, which can well assume the role of the registry and configuration center. , And then introduce how to deploy and start nacos
- Download nacos, the address is: <font color="blue"> https://github.com/alibaba/nacos/releases/download/2.0.3/nacos-server-2.0.3.zip </font>
- After decompression, enter the <font color="blue">nacos\bin</font> directory and execute the following command to start nacos:
startup.cmd -m standalone
- If your computer is mac or linux, please execute the following command to start nacos:
sh startup.sh -m standalone
- Login to nacos with the browser, the address is <font color="blue"> http://localhost:8848/nacos </font>, the account and password are both <font color="red">nacos</font>
- The following is displayed after successful login:
Source download
- The complete source code in this actual combat can be downloaded on GitHub. The address and link information are shown in the following table ( https://github.com/zq2599/blog_demos):
name | Link | Remark |
---|---|---|
Project homepage | https://github.com/zq2599/blog_demos | The project's homepage on GitHub |
git warehouse address (https) | https://github.com/zq2599/blog_demos.git | The warehouse address of the source code of the project, https protocol |
git warehouse address (ssh) | git@github.com:zq2599/blog_demos.git | The warehouse address of the source code of the project, ssh protocol |
- There are multiple folders in this git project. The source code of this article is under the <font color="blue">spring-cloud-tutorials</font> folder, as shown in the red box below:
The parent project of the "Spring Cloud Gateway Actual Combat" series
- Create a new maven project named <font color="blue">spring-cloud-tutorials</font>. This is the parent project of all the source code of the "Spring Cloud Gateway Actual Combat" series. The content of pom.xml is as follows. You can see that springboot is used here. The version numbers of the, spring-cloud, and spring-cloud-alibaba libraries have been determined, and there will be no need to pay attention to the version numbers of the dependent libraries in the future for sub-projects:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>hello-gateway</module>
<module>provider-hello</module>
<module>common</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/>
</parent>
<groupId>com.bolingcavalry</groupId>
<artifactId>spring-cloud-tutorials</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
</properties>
<packaging>pom</packaging>
<description>Demo project for Spring Cloud </description>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.9</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Create a subproject named common to store common constants and data structures
- Now create a sub-project named <font color="blue">common</font>. The constants and data structures involved in the entire "Spring Cloud Gateway Actual Combat" series are placed in this sub-project, which is convenient for other projects to use
- New constants Constants.java:
package com.bolingcavalry.common;
public interface Constants {
String HELLO_PREFIX = "Hello World";
}
Create a web application as a service provider
- Now create a web application named <font color="blue">provider-hello</font>. This is an extremely common web application that provides several http interface services. When we try the basic functions of Spring Cloud Gateway, we will Route the request to <font color="blue">provider-hello</font>
- <font color="blue">provider-hello</font> is an ordinary springboot application, which will be registered in nacos, and its pom.xml content is as follows:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tutorials</artifactId>
<groupId>com.bolingcavalry</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>provider-hello</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.bolingcavalry</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos:用于服务注册与发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 如果父工程不是springboot,就要用以下方式使用插件,才能生成正常的jar -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.bolingcavalry.provider.ProviderApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
- The configuration file application.yml of the project is as follows, the web port is <font color="red"> 8082 </font>, and one more thing to note is the nacos service address:
server:
#服务端口
port: 8082
spring:
application:
name: provider-hello
cloud:
nacos:
discovery:
# nacos服务地址
server-addr: 127.0.0.1:8848
- Start class ProviderApplication.java
package com.bolingcavalry.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
- The ordinary Controller class <font color="blue">Hello.java</font> provides an http service externally:
package com.bolingcavalry.provider.controller;
import com.bolingcavalry.common.Constants;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
@RestController
@RequestMapping("/hello")
public class Hello {
private String dateStr(){
return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
}
/**
* 返回字符串类型
* @return
*/
@GetMapping("/str")
public String helloStr() {
return Constants.HELLO_PREFIX + ", " + dateStr();
}
}
- A new test class HelloTest.java is added to check whether the service of the application is normal:
package com.bolingcavalry.provider.controller;
import com.bolingcavalry.common.Constants;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
@Slf4j
class HelloTest {
@Autowired
private MockMvc mvc;
@Test
void hello() throws Exception {
String responseString = mvc.perform(MockMvcRequestBuilders.get("/hello/str").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string(containsString(Constants.HELLO_PREFIX)))
.andDo(print())
.andReturn()
.getResponse()
.getContentAsString();
log.info("response in junit test :\n" + responseString);
}
}
- Perform a unit test (it doesn't matter whether nacos is started at this time, but there will be some error messages in the console if it is not started, but it has no effect), as follows, the test passed indicates that the service is normal:
Develop a simple demo to complete the first experience of spring-cloud-gateway
- So much preparation has been done before, and then we will invest in the development of Spring Cloud Gateway, first write a simple demo to quickly experience
- Add a new sub-project named <font color="blue">hello-gateway</font>, pom.xml is as follows, the key is to rely on <font color="red">spring-cloud-starter-gateway</font >Library, there is another important point to be careful: the test library uses reactor-test and spring-boot-starter-test, which is very different from the previous unit test, which uses webflux:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tutorials</artifactId>
<groupId>com.bolingcavalry</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hello-gateway</artifactId>
<dependencies>
<dependency>
<groupId>com.bolingcavalry</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- Here are the key points, the configuration file <font color="blue">application.yml</font> of Spring Cloud Gateway:
server:
#服务端口
port: 8081
spring:
application:
name: hello-gateway
cloud:
gateway:
routes:
- id: path_route
# 匹配成功后,会被转发到8082端口,至于端口后面的path,会直接使用原始请求的
# 例如http://127.0.0.1:8081/hello/str,会被转发到http://127.0.0.1:8082/hello/str
uri: http://127.0.0.1:8082
predicates:
# 根据请求路径中带有"/hello/",就算匹配成功
- Path=/hello/**
- If you want to forward to another domain name, you need to create a configuration class to solve the cross-domain problem:
package com.bolingcavalry.hellogateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
- Startup class:
package com.bolingcavalry.hellogateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HelloGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(HelloGatewayApplication.class,args);
}
}
- Finally, there is the unit test class. Please note that because Spring Cloud Gateway uses the webflux technology stack, the common MockMvc cannot be used to simulate requests. Several annotations are also worth noting. Also, pay attention to the usage of the expectStatus, expectBody and other APIs of WebTestClient:
package com.bolingcavalry.hellogateway;
import com.bolingcavalry.common.Constants;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest
@ExtendWith(SpringExtension.class)
@AutoConfigureWebTestClient
public class HelloTest {
@Autowired
private WebTestClient webClient;
@Test
void testHelloPredicates() {
webClient.get()
.uri("/hello/str")
.accept(MediaType.APPLICATION_JSON)
.exchange()
// 验证状态
.expectStatus().isOk()
// 验证结果,注意结果是字符串格式
.expectBody(String.class).consumeWith(result -> assertTrue(result.getResponseBody().contains(Constants.HELLO_PREFIX)));
}
}
- Please make sure that the provider-hello application has been started, and then run the HelloTest.java created above. The result is as follows. The test is passed, which proves that the function of <font color="blue">hello-gateway</font> is in line with expectations, and the successful request will be made Forward to the <font color="red">provider-hello</font> application, and successfully receive the response:
- At this point, the preparations for the "Spring Cloud Gateway actual combat" series have been completed, and a simple application experience with the most basic Spring Cloud Gateway functions has been developed. In the next article, let's practice more basic functions together.
You are not lonely, Xinchen is with you all the way
- Java series
- Spring series
- Docker series
- kubernetes series
- Database + Middleware Series
- DevOps series
Welcome to pay attention to the public account: programmer Xin Chen
Search "Programmer Xin Chen" on WeChat, I am Xin Chen, and I look forward to traveling the Java world with you...
https://github.com/zq2599/blog_demos
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。