知其然,知其所以然
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 条件装配 真实验证 动画演示
Spring 全家桶 2026-10-19

Environment 与 PropertySource:属性解析顺序与占位符

实测 Environment 与 PropertySource:系统属性 > 环境变量 > @PropertySource 文件,addFirst 赢、addLast 同名键输;MY_NAME 环境变量可以用 my.name 取;没有 PropertySourcesPlaceholderConfigurer 时缺失的 @Value 会被原样注入字面量;yes/on/1 都被转成 true;@PropertySource 读中文 .properties 默认乱码。

Spring Environment PropertySource 占位符 Value 真实验证 动画演示
Spring 全家桶 2026-10-19

FactoryBean 与 ObjectProvider:延迟与可选依赖

实测 FactoryBean 与 ObjectProvider:FactoryBean 的产品在第一次 getBean 才创建,"&名字" 取到工厂本体;isSingleton 为 false 时每次 getBean 都新建;SmartFactoryBean 的产品容器不缓存(源码里有注释);getObjectType 返回 null 就按类型找不到;ObjectProvider 在没有、一个、两个候选时 getIfAvailable / getIfUnique 的结果不同,orderedStream 按 @Order 排序,它只推迟 prototype 的创建,不推迟 singleton。

Spring FactoryBean ObjectProvider 延迟注入 可选依赖 真实验证 动画演示
Spring 全家桶 2026-10-19

事件机制:同步事件、异步事件与监听器顺序

实测 Spring 事件机制:默认同步,监听器在发布者线程里依次执行,一个失败后面的跳过且异常传回发布者;多播器配线程池后发布者 0 ms 返回、异常交给 ErrorHandler;泛型事件要实现 ResolvableTypeProvider 才按泛型匹配;在 @PostConstruct 里发布的事件会被 @EventListener 方法错过,ApplicationListener 的 Bean 却能收到。

Spring 事件 ApplicationEvent EventListener 异步事件 真实验证 动画演示
Spring 全家桶 2026-10-19

SpEL:表达式在哪些地方被求值,代价是什么

实测 SpEL:@Value("#{...}") 的引用 Bean、安全导航、静态方法调用、集合投影与过滤;null 上取属性抛 EL1007E;StandardEvaluationContext 能调 Runtime 的静态方法,SimpleEvaluationContext 拒绝;每次重新解析表达式约 1300 ns,复用解析结果约 96 ns,编译模式约 5 到 7 ns。

Spring SpEL 表达式语言 Value 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号