知其然,知其所以然
微服务 2026-10-19

服务网格里的弹性策略与应用内的区别,没有 mesh 时在应用里做同样的事

实测应用层重试和 Mesh 重试叠加的后果:一跳上两层都重试 2 次,后端收到 9 倍的请求;链上三层应用都重试是 27 倍,应用与 Envoy 都重试是 243 倍;Envoy 默认 max_retries 3 会拦下一部分重试;retry_on 5xx 会让已写入的 POST 再写一次(200 次写入对 100 个请求);超时后放弃的请求后端仍在处理。

微服务 服务网格 重试 重试风暴 幂等 超时 Envoy 真实验证 动画演示
微服务 2026-10-19

Ingress 与 Gateway API

实测 Ingress 和 Gateway API(Traefik v3.7.15,同一个数据面):Ingress 只能按 host 和 path 选一个后端,同一路径写两条规则全部去了同一个后端;HTTPRoute 的权重(90/10 得到 450/50)和请求头匹配是规范字段;跨命名空间要过 allowedRoutes 和 ReferenceGrant;HTTPRoute 状态会说明错在哪,Ingress 不会;两种写法的生效都在 0.3 s 内。

微服务 Kubernetes Ingress Gateway API HTTPRoute Traefik 真实验证 动画演示
Spring 全家桶 2026-10-19

ApplicationContext.refresh():容器启动的那十几步各做了什么

实测 ApplicationContext.refresh() 的 12 个步骤:BeanDefinition 在 invokeBeanFactoryPostProcessors 里从 6 个涨到 15 个(最慢的一步,76456 µs);BeanFactoryPostProcessor、BeanPostProcessor 本身最先被创建;普通单例在 finishBeanFactoryInitialization 里创建,prototype 与 @Lazy 的 Bean 不创建;refresh 失败时已创建的单例会被销毁。

Spring IoC ApplicationContext refresh 容器启动 真实验证 动画演示
Spring 全家桶 2026-10-19

BeanDefinition:Bean 在被创建之前是什么

实测 BeanDefinition:手写、@Component 扫描、@Bean 方法三种来源的定义类型不同(@Bean 的定义类是 null、只有 factoryMethod);BeanFactoryPostProcessor 能在创建之前把 scope 改成 prototype;子定义会和 abstract 父定义合并成 RootBeanDefinition;同名定义在纯 Spring 里默认悄悄覆盖,SpringApplication 的上下文默认不允许。

Spring IoC BeanDefinition 容器 真实验证 动画演示
Spring 全家桶 2026-10-19

Bean 生命周期:Aware、@PostConstruct、InitializingBean 与销毁回调的顺序

实测 Bean 生命周期的 15 个创建回调的顺序:BPP.beforeInstantiation → 构造器 → populate → 各种 Aware → BPP.before → @PostConstruct → afterPropertiesSet → initMethod → BPP.after;销毁顺序 @PreDestroy → destroy() → destroyMethod;prototype 关闭容器时 0 个销毁回调;@Bean 默认推断 close();初始化失败的 Bean 不会调用 @PreDestroy。

Spring Bean 生命周期 BeanPostProcessor PostConstruct 真实验证 动画演示
Spring 全家桶 2026-10-19

BeanPostProcessor 与 BeanFactoryPostProcessor:容器的两个扩展点

实测容器的两个扩展点:BeanPostProcessor 能把 Bean 换成 JDK 代理(按具体类注入就失败);多个 BPP 按 PriorityOrdered、Ordered、无顺序三组执行;被提前创建的 Bean(Early 构造器依赖 Service)不会被后注册的 BPP 处理,Spring 会打 WARN;BFPP 的 @Bean 方法非 static 时,配置类里的 @Autowired 字段是 null。

Spring BeanPostProcessor BeanFactoryPostProcessor 扩展点 真实验证 动画演示
Spring 全家桶 2026-10-19

依赖注入:构造器、setter、字段注入,@Autowired 的候选解析与 @Primary、@Qualifier

实测依赖注入的写法与候选解析:构造器、setter、字段三种方式 new 出来的差别;两个候选时 NoUniqueBeanDefinitionException,参数名、@Qualifier、@Primary、@Priority 各自能解决;两个 @Primary 仍冲突;@Order 只影响 List 的顺序;没有候选时单个依赖失败、List 是空的;泛型参数参与匹配。

Spring 依赖注入 Autowired Qualifier Primary 真实验证 动画演示
Spring 全家桶 2026-10-19

循环依赖:三级缓存解决了什么,构造器注入为什么解决不了

实测循环依赖:setter 循环能解开但 B 初始化时看到的 A 是半成品;构造器循环抛 BeanCurrentlyInCreationException;SpringApplication 默认禁止循环引用;自定义 BPP 包装让 SA、SB 各被构造了 2 次;Spring AOP 的循环会提前暴露代理;@Lazy 可以打破构造器循环。

Spring 循环依赖 三级缓存 早期引用 Lazy 真实验证 动画演示
Spring 全家桶 2026-10-19

作用域:单例里注入 prototype 的坑与 scoped proxy

实测作用域:单例里直接注入 prototype 只在创建时注入一次(id 恒为 1);ObjectProvider、@Lookup 每次拿新对象;prototype 加 scoped proxy 是每次方法调用换一个对象;thread 作用域加 scoped proxy 才是按线程稳定;单例里的 int 字段 8 线程各 200000 次 n++ 丢了 100 万次以上。

Spring 作用域 prototype scoped proxy 单例线程安全 真实验证 动画演示
Spring 全家桶 2026-10-19

@Configuration 的 CGLIB 增强与 lite 模式:@Bean 方法互相调用

实测 @Configuration 的 full 模式与 lite 模式:@Bean 方法互相调用时 full 模式只构造 1 次 A、lite 模式构造 3 次;static @Bean 不被拦截;改用方法参数注入最安全;300 个配置类把 proxyBeanMethods 设成 false,refresh 从 847 ms 降到 475 ms、少加载 1174 个类。

Spring Configuration CGLIB proxyBeanMethods Bean 真实验证 动画演示
Spring 全家桶 2026-10-19

组件扫描:@ComponentScan 的代价与元数据读取

实测组件扫描:3000 个 @Component 的 scan() 是 220 ms,但扫描时新加载的类始终是 205 个(类到实例化时才加载);包里每多一个没有注解的普通类也要被读(8000 个比 0 个多花约 357 ms,401 减 44 算出的);主类放在默认包会扫描整个 classpath 导致启动失败;同名 @Component 抛 ConflictingBeanDefinitionException。

Spring 组件扫描 ComponentScan 类元数据 真实验证 动画演示
Spring 全家桶 2026-10-19

@Conditional 系列与 Profile

实测 @Profile 与 @Conditional:没有激活 profile 时默认是 default,一旦激活别的 default 就失效;"dev & !cloud" 这样的表达式可用;“registry 里没有才注册”的条件依赖配置类顺序(User 先 [dataSource],Fallback 先 [dataSource, fallbackDs]);类级别条件在 PARSE_CONFIGURATION 阶段求值,看不到 @Bean 的定义;类上的条件会一次跳过 @Import 和嵌套配置类。

Spring Conditional Profile 条件装配 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号