Spring IOC 容器 默认注册 Bean 的 8 条规则
(Spring Framework 6.x 源码级总结)
阅读提示:把下面 8 条规则背下来,再读 Spring 源码时,你会在任何一行代码里立刻知道「这个 BeanDefinition 是从哪儿来的」。
1️⃣ 环境扫描:从 启动类所在包 向下递归
@SpringBootApplication内隐含@ComponentScan无参数 → 扫描当前包及其子包。- 源码位置:
ComponentScanAnnotationParser#parse()→ClassPathBeanDefinitionScanner#doScan()。
2️⃣ 类级别注解 自动注册
遇到下列注解即注册为 singleton Bean:
@Component(含@Service、@Repository、@Controller等元注解)@Configuration(特殊:还会生成 CGLIB 代理,见规则 4)@Bean方法所在类如果被@Configuration标注,则方法返回值也被注册。
3️⃣ @Bean 方法 注册规则
- 作用域:默认
singleton;可通过@Scope覆盖。 - 名字:
- 显式
value/name→ 直接使用 - 空 → 方法名首字母小写
- 显式
- 重载保护:同名 Bean 后注册的覆盖先注册的(
DefaultListableBeanFactory#registerBeanDefinition抛异常 → 允许覆盖开关spring.main.allow-bean-definition-overriding=true)。
4️⃣ @Configuration 特殊逻辑
- 类本身注册为 lite
@Component - 同时注册
ConfigurationClassPostProcessor,它会:- 解析
@Bean方法 - 解析
@Import(普通类、ImportSelector、ImportBeanDefinitionRegistrar) - 解析
@ComponentScan - 生成 CGLIB 代理 保证
@Bean方法内部依赖仍是单例。
- 解析
5️⃣ @Import 的三类导入
| 类型 | 注册方式 | 示例 |
|---|---|---|
| 普通类 | 直接注册 singleton | @Import(MyConfig.class) |
| ImportSelector | selectImports() 返回 String[] | @EnableCaching |
| ImportBeanDefinitionRegistrar | 手动 registry.registerBeanDefinition() | @EnableAspectJAutoProxy |
6️⃣ SPI 机制:spring.factories & META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
- Spring Boot 启动时读取
spring.factories→EnableAutoConfiguration列表 - 每个自动配置类内部再用
@Configuration+@Bean注册大量基础设施(DataSource、WebMvc、Security…)。
7️⃣ FactoryBean & BeanFactoryPostProcessor
FactoryBean#getObject()的返回值被注册,名字为&beanName(取实际对象去掉&)。BeanFactoryPostProcessor(如PropertySourcesPlaceholderConfigurer)可在注册阶段 修改 或 新增 BeanDefinition。
8️⃣ 默认单例作用域 & 延迟初始化
- 默认作用域:
singleton - 默认非延迟:容器启动即实例化;加
@Lazy则延迟到首次调用getBean()。 - 单例池:
DefaultSingletonBeanRegistry#singletonObjects(ConcurrentHashMap)。
一张图总结
启动类包扫描 → 类注解(@Component/@Configuration) → @Bean方法↓@Import(三类) → @ComponentScan → spring.factories↓ConfigurationClassPostProcessor → 注册所有BeanDefinition↓DefaultListableBeanFactory#preInstantiateSingletons → 实例化
背完这 8 条,再读 Spring 源码时,你会在任意一行 registerBeanDefinition() 前立刻定位“这是哪条规则触发”。