实测 Spring Cloud 的版本矩阵:每个发布列车的 BOM 背后的 Boot 版本(2023.0→3.3、2024.0→3.4、2025.0→3.5、2025.1→4.0);Boot 与 Cloud 大版本错配启动时是 NoClassDefFoundError,关掉兼容性校验器没用;Spring Cloud Alibaba 的版本号与 Nacos 客户端版本的对应。
实测 Spring Cloud Commons 的服务发现与注册抽象:自动注册在 Web 服务器启动之后、ApplicationRunner 与 ReadyEvent 之前发生;serviceregistry 端点的 id 与行为;enabled=false 时不创建注册相关的 bean;优雅停机时 deregister 要等在途请求处理完才执行;CompositeDiscoveryClient 如何合并多个 DiscoveryClient。
实测 Spring Cloud LoadBalancer:默认是 RoundRobinLoadBalancer,起点每次启动不同;换成 RandomLoadBalancer 短期不均匀;后端挂掉默认仍然被轮询、三分之一请求失败;health-check 缺少 RestClient bean 时全部请求 No instances available;实例列表默认被缓存约 35 秒,新实例要等这么久才被调用到。
实测 OpenFeign 的声明式客户端:@FeignClient 接口是 JDK 动态代理,在注入时创建、每个客户端名一个子上下文;Spring MVC 注解被 SpringMvcContract 解析成 HTTP 请求;只写 name 不写 url 时必须引入 loadbalancer starter,否则启动失败;一个方法两个 @RequestBody 启动即报错。
实测 OpenFeign 的超时、重试与错误解码:read-timeout 在 client.config 下按客户端名覆盖 default,超时异常是 RetryableException;默认永不重试,Retryer$Default 会对读超时的 GET 和 POST 都重试 5 次、对带 Retry-After 的 503 间隔 1 秒重试、对 500 不重试;404 默认抛 FeignException$NotFound,dismiss404 会把错误 JSON 当返回值解码而失败。
实测 Spring Cloud Gateway(WebFlux 版)的 Route、Predicate 与 Filter:谓词是「与」关系,StripPrefix / PrefixPath / SetPath / RewritePath 改后端收到的路径;默认不加 Forwarded / X-Forwarded-* 也丢掉客户端自带的,要配 trusted-proxies;order 越小越靠前;连不上后端是 500、响应超时是 504;旧属性前缀不报错但路由不生效;gateway 端点要同时配 exposure 与 access。
实测 Spring Cloud Gateway 全局过滤器的顺序:pre 按 order 从小到大、post 倒序;路由过滤器按位置从 1 编号并与全局过滤器一起排序,同为 1 时全局过滤器在前;default-filters 与路由自己的过滤器各自从 1 编号,默认的先执行;内置全局过滤器的 order(RouteToRequestUrlFilter 10000、NettyRoutingFilter 最后);不调用 chain.filter 即可短路。
实测 Spring Cloud Gateway 过滤器里的阻塞调用:2 个事件循环线程下 20 个并发请求,Thread.sleep(200) 要 2.06 秒,Mono.delay 与 boundedElastic 只要 0.22 到 0.23 秒;Mono.block() 直接抛 IllegalStateException 返回 500;默认线程数等于 CPU 核数,64 个并发请求 1.47 秒对 0.23 秒。
实测 Spring Cloud Gateway 的 RequestRateLimiter(Redis 令牌桶):burstCapacity 5、replenishRate 2 时连续 10 个请求放行 5 个并带 X-RateLimit 头;Redis 里的键带路由 id;没有 KeyResolver 返回 403;requestedTokens 加权;多实例共享计数;Redis 挂掉时默认请求卡住,配 spring.data.redis.timeout 才会放行。
实测 Spring Cloud Config Server 与 spring.config.import:配置按「应用名-profile、应用名、application」优先级合并,拼错应用名也返回 200;远程配置覆盖本地 application.properties 的同名 key;optional:configserver 连不上就悄悄用本地值,去掉 optional 才会启动失败;git 提交后服务端立即读到新值,运行中的客户端不变;{cipher} 在服务端解密后明文发给客户端。
实测 Spring Cloud 的 @RefreshScope:POST /actuator/refresh 之后只有 @RefreshScope 的 bean 和 setter 绑定的 @ConfigurationProperties 看到新值,普通单例、构造时复制值的单例、record 绑定的 @ConfigurationProperties 仍是旧值;每次刷新都销毁所有 @RefreshScope bean,哪怕什么都没改;刷新后第一个访问它的请求承担重建的耗时(400 ms 的构造函数实测 408 ms)。
实测 Spring Cloud CircuitBreaker + Resilience4j 的配置粒度:默认窗口 100、最少 100 次调用,30 次全失败也不打开;默认 TimeLimiter 只等 1 秒;configureDefault 与按 id 的 configure 逐项覆盖;先向注册表要实例会让 Customizer 失效;OPEN 后不再调用 supplier;业务异常默认也算失败;resilience4j.* 属性同样生效;每个请求一个 id 会留下 1000 个熔断器。