★ 综合题:一次 HTTP 请求在 Spring 全家桶中走完的完整链路是怎样的?

结论先行:从“用户点按钮”到“数据落库返回”,一次请求贯穿 网关层 → 服务调用层 → 业务层 → 数据层,Spring 全家桶各司其职:Gateway 路由鉴权限流、Feign+LoadBalancer 服务发现与调用、MVC 参数绑定与响应序列化、AOP/事务与 MyBatis 数据访问、缓存/消息与可观测性兜底。答题按“入口→转发→业务→数据→出口”五段讲,自然带出每个组件的关键词。

一、入口与路由(网关层)

浏览器 → Nginx/域名 → Spring Cloud Gateway
  1. 请求头解析,Predicate(Path/Host/Header)匹配路由;
  2. GlobalFilter 链:JWT 鉴权 → 非法返回 401;放行则透传 userId/traceId;
  3. RequestRateLimiter 按 IP/用户限流,超阈值 429;
  4. 匹配成功 → uri: lb://order-service 进入下一段。

二、服务发现与调用(RPC 层)

  1. LoadBalancer 从注册中心(Nacos)缓存取 order-service 实例列表,轮询选中一个实例;
  2. Feign 客户端接口代理发起 HTTP 调用,RequestInterceptor 追加 traceId/token 头;
  3. 下游不可用:熔断降级(Sentinel/Resilience4j)返回兜底,重试策略按需开启;
  4. 跨服务写多个库 → 入口 @GlobalTransactional(Seata)登记全局事务。

三、MVC 请求处理(Web 层)

Tomcat/Netty → Spring Security 过滤器链 → DispatcherServlet
  1. Spring Security:认证过滤器解析令牌写入 SecurityContext;URL 级授权过滤;
  2. DispatcherServlet → HandlerMapping 找到 @RestController 方法;
  3. 参数解析与校验:@RequestBody + Jackson 反序列化 → @Validated 校验 → 失败抛 MethodArgumentNotValidException;
  4. 进入 Controller 前可经过拦截器(鉴权/日志/幂等)。

四、业务与事务(Service 层)

  1. @Transactional 开启事务(DataSourceTransactionManager),绑定连接;
  2. MyBatis:Mapper 代理经 SqlSessionTemplate 复用事务 SqlSession,执行 SQL(#{} 预编译);
  3. 读多场景命中 @Cacheable(Redis 缓存)减少查库;写后 @CacheEvict 保证一致性;
  4. AOP 横切:日志、耗时、分布式锁(Redisson)、审计;
  5. 方法安全 @PreAuthorize 做细粒度权限,失败抛 AccessDeniedException。

五、响应与可观测(出口层)

  1. 事务提交/回滚 → Controller 返回 → Jackson 序列化 JSON → 过滤器链原路返回;
  2. 全链路 traceId 已在各服务日志 MDC,Zipkin/监控平台可检索整棵调用树;
  3. 异常统一由 @RestControllerAdvice 转成规范错误体(code/message),避免堆栈直出。

答题记忆线

入口看路由鉴权 → 调用看发现与均衡 → 业务看事务 AOP → 数据看 MyBatis/缓存 → 出口看序列化与可观测;能顺着讲清“谁在什么时候做了什么、失败由谁兜底”,即为高分答案。

常见追问 / 记忆点

  • 追问:哪些环节会加耗时,怎么排查慢请求?答:网关转发、下游 RPC、SQL、缓存/锁、序列化;按 trace 分段看 span 耗时定位。
  • 追问:这条链路上哪些点最容易出故障?答:注册中心缓存过期、下游超时无熔断、事务跨库不一致、缓存脏读——逐一对应治理组件。
  • 记忆点:五段链路“入口→调用→业务→数据→出口”,每段记一个关键词组件,再用 traceId 把整条链串起来。
笔记加载中…