举例来认识Spring Cloud API Gateway

193 阅读4分钟

什么是API?我们为什么需要它?

API网关是坐在API(应用编程接口)前面的编程,是定义的后端API和微服务(可以是内部和外部的)的单一入口点。坐在API的前面,网关起到保护作用,管理安全性和可扩展性,以及高可用性。简单地说,API网关接收来自客户的所有API请求,确定哪些服务是需要的,并将它们组合成一个统一的、无缺陷的用户体验。

API网关的优势

  • 它提高了微服务的安全性,因为我们限制外部调用对我们所有服务的访问。
  • 诸如认证、监控/指标和弹性等交叉问题只需要在API网关中实现,因为我们的所有调用都将通过它进行路由。
  • 客户不知道我们的微服务系统的内部架构。客户端将无法确定微服务实例的位置。
  • 简化了客户的互动,因为他只需要为所有的需求访问一个单一的服务。

Spring Cloud Gateway架构?

Spring Cloud Gateway是SpringCloud团队在Spring反应式生态系统之上的 API网关实现。它由以下构建模块组成:

路由:关于Apache Airflow的简介路线是网关的基本构件。它由一个ID、目的地URI、谓词集合和过滤器集合组成。如果集合谓词为真,则路由被匹配。

谓词:这类似于Java 8的函数Predicate。使用这个功能,我们可以匹配HTTP请求,如头文件、URL、cookies或参数。

过滤器:这些是Spring Framework GatewayFilter的实例。使用它,我们可以根据需求修改请求或响应。

春天云网关架构

实现Spring Cloud API Gateway

使用Spring Cloud Gateway,我们可以通过以下两种方式创建路由

  • 使用基于java的配置以编程方式创建路由
  • 使用基于属性的配置(即application.properties或application.yml)来创建路由。

在本教程中,我们将使用基于属性的配置实现Spring Cloud Gateway。
我们将实现Spring Cloud Gateway应用程序,该应用程序根据URL模式将请求路由到其他两个微服务。

实现第一个微服务

Maven项目的内容如下

pom.xml如下所示

<?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">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.2</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com</groupId>
	<artifactId>first-microservice</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>first-microservice</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
		<spring-cloud.version>2021.0.0</spring-cloud.version>

	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<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>
		</dependencies>
	</dependencyManagement>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

定义application.yml的内容如下

spring:
  application:
    name: first-microservice
server:
  port: 8081

  eureka:
   instance:
     hostname: localhost

创建一个暴露GET REST服务的控制器类,如下所示

package com.firstmicroservice.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/first")
public class FirstController {

    @GetMapping("/message")
    public String test() {
        return "Hello this is my first microservice";
    }
}

创建带有@SpringBootApplication注解的主类

package com.firstmicroservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FirstMicroserviceApplication {

	public static void main(String[] args) {
		SpringApplication.run(FirstMicroserviceApplication.class, args);
	}

}

实现第二个微服务

Maven项目的内容如下

pom.xml如下

<?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">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.2</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com</groupId>
	<artifactId>second-microservice</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>second-microservice</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
		<spring-cloud.version>2021.0.0</spring-cloud.version>

	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<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>
		</dependencies>
	</dependencyManagement>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

定义application.yml的内容如下

spring:
  application:
    name: second-microservice
server:
  port: 8082

  eureka:
    instance:
      hostname: localhost

创建一个暴露GET REST服务的控制器类,如下所示

package com.secondmicroservice.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/second")
public class SecondController {

    @GetMapping("/message")
    public String test() {
        return "Hello this is my Second Service";
    }

}

创建带有@SpringBootApplication注解的主类

package com.secondmicroservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SecondMicroserviceApplication {

	public static void main(String[] args) {
		SpringApplication.run(SecondMicroserviceApplication.class, args);
	}

}

实现Eureka服务器

Eureka服务器是一个持有信息的应用程序,在所有客户端服务应用程序之上。每个微服务都将注册到Eureka服务器,Eureka服务器知道所有在每个端口和IP地址上运行的客户端应用程序。Eureka服务器也被称为发现服务器。

构建一个Eureka服务器

Eureka服务器是与Spring Cloud捆绑在一起的。因此我们需要开发Eureka服务器,并在默认端口8761上运行。

Maven项目的内容如下

pom.xml的内容如下

<?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">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.2</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>eurekaserver</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>eurekaserver</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
		<spring-cloud.version>2021.0.0</spring-cloud.version>
	</properties>
	<dependencies>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-                  server</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<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>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

定义application.yml的内容如下

 server:
  port: 8761
 eureka:
   client:
     register-with-eureka: false
     fetch-registry: false
   server:
     waitTimeInMsWhenSyncEmpty: 0
   instance:
     hostname: localhost

创建带有@SpringBootApplication注解的主类。

package com.example.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaserverApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaserverApplication.class, args);
	}

}

使用基于属性的配置实现Spring Cloud Gateway

Maven项目的内容如下

pom.xml将如下所示

<?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">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.2</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com</groupId>
	<artifactId>springcloud-gateway</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springcloud-gateway</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
		<spring-cloud.version>2021.0.0</spring-cloud.version>
		<!--		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>-->

	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

	</dependencies>
	<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>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

定义application.yml的内容如下

server:
  port: 8080

eureka:
  instance:
   hostname: localhost

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: first-microservice
          uri: http://localhost:8081/
          predicates:
            - Path=/first/**
        - id: second-microservice
          uri: http://localhost:8082/
          predicates:
            - Path=/second/**

创建带有@SpringBootApplication注解的主类

package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class SpringcloudGatewayApplication {

	public static void main(String[] args) {

		SpringApplication.run(SpringcloudGatewayApplication.class, args);
	}

}

启动我们已经开发的三个微服务

  • 转到网址 - localhost:8080/first/message

转到URL - localhost:8080/second/message

结论

API网关是一个重要的设计概念。随着微服务数量的增加,拥有一个通用的模式变得非常重要,它可以处理这些服务的很多共同的工作负载,而API网关可以帮助实现这一点。