当前位置: 首页 > news >正文

SpringCloud Alibaba微服务--Gateway使用

一、API 网关 (Gateway) 简介

1、什么是gateway

spring cloud gateway是一个服务器端的入口点,作为客户端和后端服务之间的中间层,负责请求路由、组合和协议转换。它充当系统的"前门",所有客户端请求都首先通过API网关,然后被路由到适当的后端服务。它是建立在 Spring Boot 2.x、 Spring WebFlux 和 Project Reactor之上,旨在为微服务架构提供简单、有效和统一的API路由管理方式

2、核心功能

  • 请求路由:将客户端请求转发到相应的后端服务
  • 协议转换:处理不同协议之间的转换(如HTTP到gRPC)
  • 负载均衡:在多个服务实例之间分配请求
  • 认证授权:验证请求的合法性,检查访问权限
  • 限流熔断:控制请求速率,防止系统过载
  • 缓存:缓存常用响应,减少后端压力
  • 监控日志:记录请求指标和日志用于分析和监控
  • 请求/响应转换:修改请求或响应内容

3、gateway在微服务中的优势

  • 解耦客户端与服务端:客户端只需知道网关地址,无需了解内部服务结构
  • 简化客户端:网关可以聚合多个服务请求,减少客户端调用次数
  • 统一安全控制:集中处理认证、授权和安全策略
  • 提高性能:通过缓存、压缩和协议优化提升响应速度
  • 弹性设计:通过熔断、降级等机制提高系统可靠性
  • 易于监控:集中收集所有API调用的指标和日志

4、gateway工作流程

客户端向 Spring Cloud Gateway 发出请求。如果Gateway处理程序映射确定一个请求与路由相匹配,它将被发送到Gateway Web处理程序。这个处理程序通过一个特定于该请求的过滤器链来运行该请求。过滤器被虚线分割的原因是,过滤器可以在代理请求发送之前和之后运行逻辑。所有的 "pre" (前)过滤器逻辑都被执行。然后发出代理请求。在代理请求发出后,"post" (后)过滤器逻辑被运行。

5、Zuul实现SpringCloud网关及不足之处

在SpringCloud中网关的实现包括两种gateway、zuul。Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。二者主要区别:

对比项Spring Cloud GatewayNetflix Zuul
架构模型基于 Reactor 和 Netty 的 异步非阻塞 模型基于 Servlet 的 同步阻塞 模型
性能更高吞吐量,支持 长连接(WebFlux)性能较低,受限于 Servlet 阻塞 IO
依赖需要 Spring WebFlux 和 Project Reactor依赖 Spring MVC 和 Servlet API
功能扩展支持 自定义过滤器断言 和 全局过滤器主要依赖 Groovy 脚本扩展过滤器
协议支持支持 HTTP/2WebSocketgRPC仅支持 HTTP/1.x
服务发现原生支持 EurekaConsulNacos需配合 Netflix Eureka 使用
负载均衡集成 Ribbon 或 Spring Cloud LoadBalancer依赖 Ribbon
熔断限流支持 HystrixResilience4jSentinel主要依赖 Hystrix
配置方式YAML/Properties + Java DSL(更灵活)主要依赖 Groovy 脚本或 Java 配置
社区支持Spring 官方维护,持续更新Netflix 已停止维护(Zuul 1.x)
适用场景高并发低延迟 的微服务网关传统 同步阻塞 架构的简单网关

二、构建SpringCloud Gateway服务

1、新建子模块jd-shop-gateway服务

微服务搭建以及nacos注册和配置方式可以参考之前的文章:

SpringCloud Alibaba微服务框架搭建-CSDN博客

SpringCloud Alibaba微服务--Nacos注册中心和配置中心应用-CSDN博客

2、引入依赖

       <dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId><version>3.0.7</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>${spring-cloud-alibaba.version}</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>${spring-cloud-alibaba.version}</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId><version>3.0.2</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><dependency><groupId>com.mdx</groupId><artifactId>mdx-shop-common</artifactId><version>1.0.0</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-loadbalancer</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-commons</artifactId></dependency></dependencies>

3、编写基础配置和路由规则

(1)路由基础配置

  1. 路由id:路由的唯一标示

  2. 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡

  3. 路由断言(predicates):判断路由的规则,

  4. 路由过滤器(filters):对请求或响应做处理

(2)设置bootstrap.yml配置文件

server:port: 8091spring:application:name: jd-shop-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848namespace: jdconfig:server-addr: 127.0.0.1:8848extension-configs:- data-id: ${spring.application.name}.yamlgroup: DEFAULT_GROUPrefresh: truefile-extension: ymlnamespace: jdgroup: DEFAULT_GROUPgateway:discovery:locator:enabled: truelower-case-service-id: trueroutes:- id: mdx-shop-user             #路由的ID,没有固定规则但要求唯一,建议配合服务名uri: http://127.0.0.1:8021       #匹配后提供服务的路由地址predicates:- Path=/user/**    #断言,路径相匹配的进行路由- id: mdx-shop-orderuri: http://127.0.0.1:8081predicates:- Path=/order/**main:web-application-type: reactive

4、重启服务,测试访问接口

通过gateway访问user服务,访问地址http://localhost:8091/user/getOrderNo?userId=T1234

8091为网关端口号

通过gateway访问order服务,访问地址http://127.0.0.1:8091/order/getOrderId?userId=T1234

8091为网关端口号

5、通过微服务名称的形式进行路由

将uri: http://127.0.0.1:8021 换成 uri: lb://jd-shop-user形式

重启服务,在测试一下user服务接口,访问

http://localhost:8091/user/getOrderNo?userId=T1234

8091为网关端口号

6、测试负载均衡

采用这种路由方式 uri: lb://jd-shop-user
在gateway添加配置:
开启通过服务中心的自动根据 serviceId 创建路由的功能

discovery:
        locator:
          enabled: true
          lower-case-service-id: true

启动两个order服务,为另一个order服务新开一个端口号

启动两个order服务

nacos中可以看到有两个order服务实例

通过gateway访问order服务,访问地址http://127.0.0.1:8091/order/getOrderId?userId=T1234

可以发现访问的是OrderApplication服务接口

再次访问接口,发现访问的是OrderApplication2服务接口,实现了简单的负载均衡

三、通过nacos实现动态路由

对于微服务来说,如果使用配置文件来管理路由规则的话,每增加一个服务或者修改一个服务,都需要重启gateway服务,这样很麻烦,因此我们通过nacos来动态配置路由,就不需要进行服务重启了,编写对应的配置类,实现自动监听nacos配置文件的更新,实现动态刷新。

1、创建路由配置类

新建路由发布接口

public interface RouteService {/*** 添加路由信息* @return*/void addRoute(RouteDefinition routeDefinition);/*** 修改路由信息* @return*/void updateRoute(RouteDefinition routeDefinition);/*** 删除路由信息* @return*/void deleteRoute(String routeId);
}

新建RouteServiceImpl类实现接口

@Service
@Slf4j
public class RouteServiceImpl implements RouteService, ApplicationEventPublisherAware {@Autowiredprivate RouteDefinitionWriter routeDefinitionWriter;/*** 事件发布者*/private ApplicationEventPublisher publisher;@Overridepublic void addRoute(RouteDefinition routeDefinition) {log.info("添加路由:{}", routeDefinition);routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();this.publisher.publishEvent(new RefreshRoutesEvent(this));}@Overridepublic void updateRoute(RouteDefinition routeDefinition) {log.info("更新路由:{}", routeDefinition);routeDefinitionWriter.delete(Mono.just(routeDefinition.getId())).subscribe();routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();this.publisher.publishEvent(new RefreshRoutesEvent(this));}@Overridepublic void deleteRoute(String routeId) {log.info("删除路由:{}", routeId);routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();this.publisher.publishEvent(new RefreshRoutesEvent(this));}@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.publisher = applicationEventPublisher;}
}

2、在nacos创建gateway-routes配置文件

(1)新建配置

json内容对应着RouteDefinition 类,Json内容:

[{"predicates":[{"args":{"pattern":"/order/**"},"name":"Path"}],"id":"jd-shop-order","uri":"lb://jd-shop-order","order":1},{"predicates":[{"args":{"pattern":"/user/**"},"name":"Path"}],"id":"jd-shop-user","uri":"lb://jd-shop-user","order":2}
]

这里面博主没有加过滤链:

 "filters":[
            {
                "args":{
                    "parts":1
                },
                "name":"StripPrefix"  
            }
        ],

作用:当请求路径为 /api/user 时,网关会截掉第一个路径部分(/api),将请求转发到后端服务时路径变为 /user

(2)修改bootstrap.yml配置文件,添加路由配置文件dataId、group等,之前路由规则删除或注释掉。

server:port: 8091spring:application:name: jd-shop-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848namespace: jdconfig:server-addr: 127.0.0.1:8848extension-configs:- data-id: ${spring.application.name}.yamlgroup: DEFAULT_GROUPrefresh: truefile-extension: ymlnamespace: jdgroup: DEFAULT_GROUPgateway:discovery:locator:enabled: truelower-case-service-id: true
#      routes:
#        - id: jd-shop-user             #路由的ID,没有固定规则但要求唯一,建议配合服务名
#          uri: lb://jd-shop-user       #匹配后提供服务的路由地址
##          uri: http://127.0.0.1:8021
#          predicates:
#            - Path=/user/**    #断言,路径相匹配的进行路由
#
#        - id: jd-shop-order
#          uri: lb://jd-shop-order
##          uri: http://127.0.0.1:8081
#          predicates:
#            - Path=/order/**main:web-application-type: reactivegateway:routes:config:data-id: gateway-routes  #动态路由group: DEFAULT_GROUPnamespace: jd

3、创建路由相关配置类

(1)创建配置类引入配置

@ConfigurationProperties(prefix = "gateway.routes.config")
@Component
@Data
public class GatewayRoutesConfigProperties {private String dataId;private String group;private String namespace;
}


(2)实例化nacos的ConfigService,交由springbean管理

@Configuration
public class GatewayServiceConfig {@Autowiredprivate GatewayRoutesConfigProperties configProperties;@Autowiredprivate NacosConfigProperties nacosConfigProperties;@Beanpublic ConfigService configService() throws NacosException {Properties properties = new Properties();properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosConfigProperties.getServerAddr());properties.setProperty(PropertyKeyConst.NAMESPACE, configProperties.getNamespace());return NacosFactory.createConfigService(properties);}}

(3)路由监听类实现,项目启动时会加载这个类
@PostConstruc 注解的作用,在spring bean的生命周期依赖注入完成后被调用的方法

@Component
@Slf4j
@RefreshScope
public class GatewayRouteInitConfig {@Autowiredprivate GatewayRoutesConfigProperties configProperties;@Autowiredprivate NacosConfigProperties nacosConfigProperties;@Autowiredprivate RouteService routeService;/*** nacos 配置服务*/@Autowiredprivate ConfigService configService;/*** JSON 转换对象*/private final ObjectMapper objectMapper = new ObjectMapper();@PostConstructpublic void init() {log.info("开始网关动态路由初始化...");try {// getConfigAndSignListener()方法 发起长轮询和对dataId数据变更注册监听的操作// getConfig 只是发送普通的HTTP请求String initConfigInfo = configService.getConfigAndSignListener(configProperties.getDataId(), configProperties.getGroup(), nacosConfigProperties.getTimeout(), new Listener() {@Overridepublic Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String configInfo) {if (StringUtils.isNotEmpty(configInfo)) {log.info("接收到网关路由更新配置:\r\n{}", configInfo);List<RouteDefinition> routeDefinitions = null;try {routeDefinitions = objectMapper.readValue(configInfo, new TypeReference<List<RouteDefinition>>() {});} catch (JsonProcessingException e) {log.error("解析路由配置出错," + e.getMessage(), e);}for (RouteDefinition definition : Objects.requireNonNull(routeDefinitions)) {routeService.updateRoute(definition);}} else {log.warn("当前网关无动态路由相关配置");}}});log.info("获取网关当前动态路由配置:\r\n{}", initConfigInfo);if (StringUtils.isNotEmpty(initConfigInfo)) {List<RouteDefinition> routeDefinitions = objectMapper.readValue(initConfigInfo, new TypeReference<List<RouteDefinition>>() {});for (RouteDefinition definition : routeDefinitions) {routeService.addRoute(definition);}} else {log.warn("当前网关无动态路由相关配置");}log.info("结束网关动态路由初始化...");} catch (Exception e) {log.error("初始化网关路由时发生错误", e);}}
}

4、测试动态路由

(1)重启服务,通过gateway访问order服务,访问地址http://127.0.0.1:8091/order/getOrderId?userId=T1234

8091为网关端口号

(2)在nacos配置中添加user服务路由规则,点击发布后,gateway的监听器已经监听到配置的改动

在不重启gateway服务前提下,通过gateway访问user服务,访问地址http://localhost:8091/user/getOrderNo?userId=T12345

可以看到成功路由到对应服务

SpringCloud Gateway网关服务就介绍到这里,创作不易,记得点赞收藏哟

上一篇文章:

SpringCloud Alibaba微服务--Sentinel的使用-CSDN博客


文章转载自:

http://V3tRPxD5.nfpkx.cn
http://xe0nSQjf.nfpkx.cn
http://UyOSOeEM.nfpkx.cn
http://ExJUPXH0.nfpkx.cn
http://KcHyDbbg.nfpkx.cn
http://fZz8E3gG.nfpkx.cn
http://otQ3nx8J.nfpkx.cn
http://XS9E9pjb.nfpkx.cn
http://WQlQahYV.nfpkx.cn
http://uK5VrDTU.nfpkx.cn
http://WjDHQb7W.nfpkx.cn
http://3ziqJlVS.nfpkx.cn
http://BwTcF5RT.nfpkx.cn
http://LpDyx17u.nfpkx.cn
http://6REuLmu7.nfpkx.cn
http://ew9UY2cJ.nfpkx.cn
http://MIHNJCyi.nfpkx.cn
http://7af3yB9E.nfpkx.cn
http://lDX6Jjkb.nfpkx.cn
http://3RYVwulL.nfpkx.cn
http://585U9sxX.nfpkx.cn
http://KdsGB0e1.nfpkx.cn
http://P4Wn9acL.nfpkx.cn
http://mfDndDeF.nfpkx.cn
http://sIIrUy4u.nfpkx.cn
http://mUdoSrTL.nfpkx.cn
http://wAAqF2Hx.nfpkx.cn
http://CoKkOjMB.nfpkx.cn
http://Q0OUvVJt.nfpkx.cn
http://hc13fqiN.nfpkx.cn
http://www.dtcms.com/a/371313.html

相关文章:

  • 基于脚手架微服务的视频点播系统-播放控制部分
  • 【C++详解】C++ 智能指针:使用场景、实现原理与内存泄漏防治
  • 【iOS】push,pop和present,dismiss
  • HiCMAE 论文复现:基于 RAVDESS 数据集的音视频情感识别
  • axios的两种异步方式对比
  • uniapp结合uview制作美食页面
  • Spark mapreduce 的一个用法
  • [iOS] push 和 present Controller 的区别
  • 五.贪心算法
  • vue中axios与fetch比较
  • 【iOS】block复习
  • 打造第二大脑读书笔记目录
  • 【Docker】Docker基础
  • 一、CMake基础
  • 【音视频】WebRTC P2P、SFU 和 MCU 架构
  • VBA 自动转化sheet到csv文件
  • rabbitmq 重试机制
  • 《C++进阶之STL》【set/map 使用介绍】
  • 【RabbitMQ】----初识 RabbitMQ
  • WebRTC开启实时通信新时代
  • JVM-默背版
  • Java内存区域与内存溢出
  • Python3使用Flask开发Web项目新手入门开发文档
  • 深入理解跳表:多层索引加速查找的经典实现
  • 从 “Hello AI” 到企业级应用:Spring AI 如何重塑 Java 生态的 AI 开发
  • 大模型架构演进全景:从Transformer到下一代智能系统的技术路径(MoE、Mamba/SSM、混合架构)
  • leetcode 912 排序数组(归并排序)
  • Flutter SDK 安装与国内镜像配置全流程(Windows / macOS / Linux)
  • 【算法】92.反转链表Ⅱ--通俗讲解
  • Spring Cloud Alibaba快速入门02-Nacos(上)