GateWay使用

本文介绍了如何在Spring Cloud Gateway中配置路由、负载均衡、路由断言和过滤器,展示了如何通过YAML配置文件设置服务发现和路由到不同的微服务实例。同时,提到了Eureka作为服务注册与发现组件的使用。

引入依赖

<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>

配置yml

server:
  port: 9999 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: pi-service1 # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: http://localhost:8001 # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
        - id: api-service2
          uri: http://localhost:8002
          predicates:
            - Path=/order/**

同上

server:
  port: 10001 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    gateway:
      routes: # 网关路由配置
        - id: api-service1 # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://api-service1 # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/product/** # 这个是按照路径匹配,只要以/product/开头就符合要求
          filters:
            - AddRequestHeader=token,wahahaawahaha
            - AddRequestParameter=username, ergou
            - SetStatus=404
            # - RewritePath=/red(?<segment>/?.*), $\{segment}
            - StripPrefix=2
        - id: api-service2
          uri: lb://api-service2
          predicates:
            - Path=/order/**
eureka:
  client:
    service-url:
      defalutZone: http://localhost:8761/eureka

properties

server.port=9999
spring.application.name=gateway
spring.cloud.nacos.server-addr=localhost:8848
spring.cloud.gateway.routes[0].id=pi-service1
spring.cloud.gateway.routes[0].uri=http://localhost:8001
spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**
spring.cloud.gateway.routes[1].id=api-service2
spring.cloud.gateway.routes[1].uri=http://localhost:8002
spring.cloud.gateway.routes[1].predicates[0]=Path=/order/**

你提到“Gateway使用”,结合之前的上下文(事务、拦截器、日志等),我理解你现在可能是在一个 **Spring Cloud Gateway** 环境中,想要实现类似的功能:比如在请求处理完成后记录日志、上传 FTP 日志文件,或者控制某些操作在事务之后执行。 但需要注意的是: > ❗ Spring Cloud Gateway 是基于 **WebFlux** 和 **Reactor** 的响应式网关,它**没有 `HandlerInterceptor`**,也不支持传统的 `@Transactional` 声明式事务或编程式事务模板直接使用。 因此,原来在 Spring MVC 中使用的 `FtpLogInterceptor`、`TransactionInterceptor`、`TransactionTemplate` 等机制,在 Gateway 中需要重新设计。 --- ### 回答问题:如何在 Spring Cloud Gateway 中正确使用,并实现“在事务提交后执行日志上传”? #### ✅ 实际情况分析: 1. **Gateway 不是业务服务层** 它的主要职责是路由、过滤、限流、鉴权等,不建议在 Gateway 中进行数据库事务操作。 2. **无法使用 `@Transactional`** 因为 WebFlux + Reactor 不支持 Spring 的传统事务传播机制(基于 ThreadLocal)。如果你强行注入 `TransactionTemplate`,会遇到: - 不兼容阻塞操作 - 事务上下文丢失 - 异常回滚失效 3. **替代方案:使用全局过滤器(GlobalFilter)+ 异步通知机制** --- ### 推荐做法:使用 `GlobalFilter` 记录请求日志,并通过异步方式上传 FTP(模拟“事务后”行为) #### 示例代码:自定义全局过滤器,在请求完成后记录日志并触发 FTP 上传 ```java @Component @Order(-1) public class FtpLogGlobalFilter implements GlobalFilter { private final ExecutorTaskExecutor taskExecutor; public FtpLogGlobalFilter() { // 使用独立线程池避免阻塞事件循环 this.taskExecutor = new ExecutorTaskExecutor(Executors.newFixedThreadPool(4)); } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { long startTime = System.currentTimeMillis(); // 使用 Mono.defer 包装链式调用,确保后续逻辑可被订阅 return chain.filter(exchange) .doOnSuccessOrError((unused, throwable) -> { long duration = System.currentTimeMillis() - startTime; String uri = exchange.getRequest().getURI().toString(); String method = exchange.getRequest().getMethodValue(); int status = exchange.getResponse().getStatusCode() != null ? exchange.getResponse().getStatusCode().value() : 0; // 构建日志对象 AccessLog log = new AccessLog(method, uri, duration, status, new Date()); // 模拟“事务提交后”的行为:异步上传 FTP if (throwable == null) { // 只有成功完成才上传 uploadLogToFTPAsync(log); } }); } private void uploadLogToFTPAsync(AccessLog log) { taskExecutor.execute(() -> { try { // 模拟 FTP 上传 System.out.println("Uploading log to FTP: " + log); Thread.sleep(200); // 模拟网络延迟 } catch (Exception e) { e.printStackTrace(); } }); } // 内部类:用于包装线程池的 TaskExecutor static class ExecutorTaskExecutor implements TaskExecutor { private final Executor executor; public ExecutorTaskExecutor(Executor executor) { this.executor = executor; } @Override public void execute(Runnable task) { executor.execute(task); } } // 日志实体类 static class AccessLog { private String method; private String uri; private long responseTimeMs; private int statusCode; private Date timestamp; public AccessLog(String method, String uri, long responseTimeMs, int statusCode, Date timestamp) { this.method = method; this.uri = uri; this.responseTimeMs = responseTimeMs; this.statusCode = statusCode; this.timestamp = timestamp; } @Override public String toString() { return "AccessLog{" + "method='" + method + '\'' + ", uri='" + uri + '\'' + ", responseTimeMs=" + responseTimeMs + ", statusCode=" + statusCode + ", timestamp=" + timestamp + '}'; } } } ``` --- ### 配置说明: 确保启用 Gateway 并添加依赖: #### `pom.xml` 示例: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> ``` #### `application.yml` 示例: ```yaml spring: cloud: gateway: routes: - id: user_service uri: http://localhost:8081 predicates: - Path=/api/users/** ``` --- ### 解释总结: - Spring Cloud Gateway 使用的是 **响应式编程模型(Reactor)**,不能使用传统的 `HandlerInterceptor`。 - 使用 `GlobalFilter` 替代拦截器功能。 - 在 `.doOnSuccessOrError()` 中可以实现“请求完成后的操作”,相当于 MVC 中的 `afterCompletion`。 - 由于不能使用 `@Transactional`,所以所谓“事务之后”应理解为:**业务服务返回成功后,再执行副作用操作(如日志上传)**。 - FTP 上传必须异步执行,避免阻塞 Netty 的事件循环线程。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值