★ 综合题:一次 HTTP 请求在 Spring 全家桶中走完的完整链路是怎样的?
结论先行:从“用户点按钮”到“数据落库返回”,一次请求贯穿 网关层 → 服务调用层 → 业务层 → 数据层,Spring 全家桶各司其职:Gateway 路由鉴权限流、Feign+LoadBalancer 服务发现与调用、MVC 参数绑定与响应序列化、AOP/事务与 MyBatis 数据访问、缓存/消息与可观测性兜底。答题按“入口→转发→业务→数据→出口”五段讲,自然带出每个组件的关键词。
一、入口与路由(网关层)
浏览器 → Nginx/域名 → Spring Cloud Gateway
- 请求头解析,Predicate(Path/Host/Header)匹配路由;
- GlobalFilter 链:JWT 鉴权 → 非法返回 401;放行则透传 userId/traceId;
- RequestRateLimiter 按 IP/用户限流,超阈值 429;
- 匹配成功 → uri: lb://order-service 进入下一段。
二、服务发现与调用(RPC 层)
- LoadBalancer 从注册中心(Nacos)缓存取 order-service 实例列表,轮询选中一个实例;
- Feign 客户端接口代理发起 HTTP 调用,RequestInterceptor 追加 traceId/token 头;
- 下游不可用:熔断降级(Sentinel/Resilience4j)返回兜底,重试策略按需开启;
- 跨服务写多个库 → 入口 @GlobalTransactional(Seata)登记全局事务。
三、MVC 请求处理(Web 层)
Tomcat/Netty → Spring Security 过滤器链 → DispatcherServlet
- Spring Security:认证过滤器解析令牌写入 SecurityContext;URL 级授权过滤;
- DispatcherServlet → HandlerMapping 找到 @RestController 方法;
- 参数解析与校验:@RequestBody + Jackson 反序列化 → @Validated 校验 → 失败抛 MethodArgumentNotValidException;
- 进入 Controller 前可经过拦截器(鉴权/日志/幂等)。
四、业务与事务(Service 层)
- @Transactional 开启事务(DataSourceTransactionManager),绑定连接;
- MyBatis:Mapper 代理经 SqlSessionTemplate 复用事务 SqlSession,执行 SQL(#{} 预编译);
- 读多场景命中 @Cacheable(Redis 缓存)减少查库;写后 @CacheEvict 保证一致性;
- AOP 横切:日志、耗时、分布式锁(Redisson)、审计;
- 方法安全 @PreAuthorize 做细粒度权限,失败抛 AccessDeniedException。
五、响应与可观测(出口层)
- 事务提交/回滚 → Controller 返回 → Jackson 序列化 JSON → 过滤器链原路返回;
- 全链路 traceId 已在各服务日志 MDC,Zipkin/监控平台可检索整棵调用树;
- 异常统一由 @RestControllerAdvice 转成规范错误体(code/message),避免堆栈直出。
答题记忆线
入口看路由鉴权 → 调用看发现与均衡 → 业务看事务 AOP → 数据看 MyBatis/缓存 → 出口看序列化与可观测;能顺着讲清“谁在什么时候做了什么、失败由谁兜底”,即为高分答案。
常见追问 / 记忆点
- 追问:哪些环节会加耗时,怎么排查慢请求?答:网关转发、下游 RPC、SQL、缓存/锁、序列化;按 trace 分段看 span 耗时定位。
- 追问:这条链路上哪些点最容易出故障?答:注册中心缓存过期、下游超时无熔断、事务跨库不一致、缓存脏读——逐一对应治理组件。
- 记忆点:五段链路“入口→调用→业务→数据→出口”,每段记一个关键词组件,再用 traceId 把整条链串起来。