在微服务架构中,为了提高系统的可维护性和可扩展性,通常会将独立的业务或功能划分为不同的服务。这些微服务彼此隔离,并且可以独立地进行部署和升级。为了集中管理这些微服务,服务注册中心被引入。
对于外部用户请求,在处理核心业务逻辑之前,通常需要进行一些预处理操作,例如权限验证、监控统计和流量限制等。如果每个外部请求都直接发送给微服务,那么每个服务都需要处理这些预处理操作,这会导致这些功能逻辑在各个服务中重复出现,增加了未来的维护和升级成本。
为了解决这个问题,网关组件在微服务架构中被引入作为请求的入口点。网关可以集中处理一些基础的请求预处理逻辑,从而避免了在各个业务服务中重复实现这些功能。这使得业务服务能够专注于处理核心业务逻辑,提高了系统的效率和可维护性。
此外,引入网关作为统一请求入口之后,还可以利用网关实现其他功能,例如服务保护和灰度发布等。通过网关的集中管理和控制,可以实现更加灵活和强大的系统功能。
总之,在微服务架构中,网关组件扮演着重要的角色,它作为请求的入口点,提供了基础的请求预处理功能,简化了业务服务的实现,并增加了系统的可维护性和可扩展性。
Spring Cloud Gateway 通过与 Spring Cloud 的其他组件如 Spring Cloud Config、Spring Cloudsle、Eureka 等集成,能够更轻松地实现上述功能。它提供了丰富的路由、过滤器、断路器等编程模型,允许开发者根据实际需求定制网关的行为。此外,由于它是基于 Spring Boot 的,所以可以利用 Spring Boot 的特性如自动配置、生产准备等来提升应用的质量和稳定性。
微服务网关通常可以提供以下功能:
请求路由:根据请求的 URL、协议、参数等信息,将请求路由到相应的微服务。
请求限流:对微服务的请求流量进行限制,防止流量过载导致服务崩溃。
请求过滤:在请求到达微服务之前或之后,进行一些处理,例如日志记录、权限校验、数据转换等。
熔断降级:在微服务出现故障或性能问题时,自动降级并返回适当的错误信息或备用数据。
服务发现:自动感知微服务的注册与注销信息,动态更新路由规则。
动态配置:根据环境、版本等因素动态调整路由、限流等配置。
安全控制:对进入微服务的请求进行安全校验,例如身份认证、API 密钥等。
监控与日志:收集网关的请求日志和性能指标,以便进行监控和问题排查。
Route 路由:gateway的基本构建模块。它由id、目标uri、predicates集合和 filters集合组成。如果聚合谓词为true,则匹配路由。
Predicate 断言:表示路由的匹配条件,可以用来匹配请求的各种属性,如请求路径、方法、header 等。一个 Route 可以包含多个子 Predicates,多个子 Predicates 最终会合并成一个;
Filter 过滤器:过滤器包括了处理请求和响应的逻辑,可以分为 pre 和 post 两个阶段。多个 Filter 在 pre 阶段会按优先级高到低顺序执行,post 阶段则是反向执行。
客户端向Spring Cloud Gateway发出请求。如果Gateway Handler Mapping确定请求与路由匹配,则将其发送到Gateway Web Handler。此handler通过特定于该请求的过滤器链处理请求。图中filters被虚线划分的原因是filters可以在发送代理请求之前或之后执行逻辑。先执行所有“pre filter”逻辑,然后进行请求代理。在请求代理执行完后,执行“post filter”逻辑。
详细地介绍了Spring Cloud Gateway处理请求的流程。以下是这段内容的概述和重点:
客户端发送请求到网关:这是请求处理的起始点,客户端(如浏览器、移动应用等)发送HTTP请求到Spring Cloud Gateway服务器。
请求被处理并组装成网关上下文:请求进入网关后,首先被HttpWebHandlerAdapter处理。这个组件提取HTTP请求信息,并将其组装成网关上下文对象,其中包含各种请求信息,如HTTP头、请求参数等。
网关上下文传递到DispatcherHandler:组装好的网关上下文被传递到DispatcherHandler,这是Spring Cloud Gateway的核心处理器。它的任务是将请求分发到合适的处理程序。
路由查找与判断:RoutePredicateHandlerMapping负责路由查找。根据网关上下文中的信息,它选择适当的路由。每个路由都包含一个或多个路由断言,这些断言用于判断该路由是否适用于当前请求。
过滤器链的创建与调用:如果路由断言成功,表示当前请求匹配了某个路由规则。FilteringWebHandler会创建一个过滤器链,并按照链的顺序调用这些过滤器。这些过滤器可以在请求到达后端服务之前或响应返回给客户端之前对请求进行修改、验证或记录日志等操作。
推荐使用阿里云脚手架,可以省去查看开源框架版本之间的问题。
项目地址gitee: micro-practice
pom
<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.0modelVersion>
<groupId>com.gitee.xmhzzzgroupId>
<artifactId>micro-practiceartifactId>
<version>1.0.0-SNAPSHOTversion>
<packaging>pompackaging>
<name>micro-practicename>
<description>micro-practicedescription>
<modules>
<module>gateway-servicemodule>
<module>gateway-quick-startmodule>
<module>demo-servicemodule>
modules>
<properties>
<java.version>17java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>3.0.2spring-boot.version>
<spring-cloud-alibaba.version>2022.0.0.0spring-cloud-alibaba.version>
<spring-cloud.version>2022.0.0spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>${spring-cloud-alibaba.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<source>17source>
<target>17target>
<encoding>UTF-8encoding>
configuration>
plugin>
plugins>
build>
<repositories>
<repository>
<id>spring-milestonesid>
<name>Spring Milestonesname>
<url>https://repo.spring.io/milestoneurl>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
repositories>
project>
pom
<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.0modelVersion>
<parent>
<groupId>com.gitee.xmhzzzgroupId>
<artifactId>micro-practiceartifactId>
<version>1.0.0-SNAPSHOTversion>
parent>
<artifactId>demo-serviceartifactId>
<properties>
<maven.compiler.source>17maven.compiler.source>
<maven.compiler.target>17maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-bootstrapartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<configuration>
<mainClass>com.gitee.xmhzzz.demo.service.DemoServiceApplicationmainClass>
<skip>trueskip>
configuration>
<executions>
<execution>
<id>repackageid>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
project>
pom
<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.0modelVersion>
<parent>
<groupId>com.gitee.xmhzzzgroupId>
<artifactId>micro-practiceartifactId>
<version>1.0.0-SNAPSHOTversion>
parent>
<artifactId>gateway-quick-startartifactId>
<properties>
<maven.compiler.source>17maven.compiler.source>
<maven.compiler.target>17maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-bootstrapartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<configuration>
<mainClass>com.gitee.xmhzzz.gateway.quick.start.GatewayQuickStartApplicationmainClass>
<skip>trueskip>
configuration>
<executions>
<execution>
<id>repackageid>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
project>
Spring Cloud Gateway将路由作为Spring WebFlux HandlerMapping基础结构的一部分进行匹配。Spring Cloud Gateway包含许多内置的路由断言Factories。这些断言都匹配HTTP请求的不同属性。多个路由断言Factories可以通过 and 组合使用。
@Slf4j
@RestController
@RequestMapping("/demo/test/gateway")
public class DemoController {
@GetMapping("/yaml")
public void testYaml(){
log.info("testGateway yaml");
}
@GetMapping("/bean")
public void testBean(){
log.info("testGateway bean");
}
}
spring:
cloud:
gateway:
routes:
- id: demo-service
uri: http://127.0.0.1:8003/demo-service/demo/test/gateway/yaml
predicates:
- Path=/demo-server/demo/test/gateway/yaml
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes =routeLocatorBuilder.routes();
routes.route("demo-service1",r -> r.path("/demo-service/demo/test/gateway/bean").uri("http://127.0.0.1:8003/demo-service/demo/test/gateway/bean"));
return routes.build();
}
}
Gateway还提供了自动路由规则,具体配置如下:
gateway.discovery.locator.enabled = true 这个配置默认为false,但是如果设置为true就是开启了通过serviceID转发到具体的服务实例。
配置好之后,可以直接通过服务名称来进行访问Nacos中注册的服务和对应接口。
Gateway在开启了自动路由之后还自带负载均衡功能。
注意:使用nacos做注册中心,因为nacos剔除负载均衡组件Ribbon。pom需要添加loadbalancer
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: 9b02d316-10f4-40bc-b06b-32cd0e6b3732
group: DEV_GROUP
service: ${spring.application.name}
password: nacos
username: nacos
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: 9b02d316-10f4-40bc-b06b-32cd0e6b3732
group: DEV_GROUP
service: ${spring.application.name}
password: nacos
username: nacos
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: demo-service
uri: lb://demo-service
predicates:
- Path=/demo-server/demo/test/gateway/yaml