Spring如何把bean注册到容器里

1.把bean都注册到spring容器的流程是什么

好问题!你问的是 Bean注册流程,这和加载流程是"前与后"的关系。

简单区分:

  • 注册 :把Bean的定义信息(BeanDefinition)放进容器
  • 加载:根据定义信息创建出对象实例

注册的几种入口方式

方式 注册入口 典型场景
XML配置 XmlBeanDefinitionReader 老项目、Spring 2.x
注解配置类 AnnotatedBeanDefinitionReader @Configuration + @Bean
组件扫描 ClassPathBeanDefinitionScanner @Component@Service
编程式注册 GenericBeanDefinition + registerBeanDefinition Spring Boot自动配置、自定义starter
Import导入 @Import 手动导入配置类或ImportSelector

核心流程图(以注解扫描为例)

复制代码
启动Spring容器
    ↓
new AnnotationConfigApplicationContext(Config.class)
    ↓
【阶段1】读取配置类 → 注册配置类自身
    ↓
【阶段2】处理@Bean方法 → 每个@Bean生成一个BeanDefinition
    ↓
【阶段3】执行@ComponentScan → 扫描包下所有带注解的类
    ↓
【阶段4】处理@Import、@ImportResource等
    ↓
【阶段5】所有BeanDefinition注册到BeanDefinitionRegistry
    ↓
【阶段6】调用refresh() → 开始Bean加载(实例化、初始化...)

详细步骤拆解(源码视角)

1. 容器启动

java 复制代码
AnnotationConfigApplicationContext context = 
    new AnnotationConfigApplicationContext(AppConfig.class);

构造函数内部:

java 复制代码
// 1. 创建 DefaultListableBeanFactory(核心注册中心)
// 2. 创建 AnnotatedBeanDefinitionReader(处理@Bean等)
// 3. 创建 ClassPathBeanDefinitionScanner(处理@ComponentScan)
// 4. 调用 refresh()

2. 注册配置类本身

AnnotatedBeanDefinitionReaderAppConfig.class 转成 AnnotatedGenericBeanDefinition

  • beanName = "appConfig"
  • beanClass = AppConfig.class
  • 标记为 @Configuration

3. 处理 @ComponentScan

ClassPathBeanDefinitionScanner 扫描指定包:

  • 找到所有带 @Component@Service@Repository@Controller 的类
  • 每个类生成 ScannedGenericBeanDefinition
  • 解析 @Scope@Lazy@Primary 等元数据

4. 处理 @Bean 方法

ConfigurationClassPostProcessor(BeanFactoryPostProcessor):

  • 解析 @Configuration 类中的 @Bean 方法
  • 每个 @Bean 方法生成 ConfigurationClassBeanDefinition
  • beanName = 方法名(默认)或 @Bean("name") 指定的

5. 处理 @Import

三种情况:

@Import的值 处理方式
普通类 直接注册
ImportSelector 调用 selectImports() 返回类名数组,逐个注册
ImportBeanDefinitionRegistrar 调用 registerBeanDefinitions(),编程式注册

6. 注册到 BeanDefinitionRegistry

所有 BeanDefinition 最终都存入 DefaultListableBeanFactory 的:

java 复制代码
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

7. 等待 refresh() 触发加载

注册完成后,refresh() 中的 finishBeanFactoryInitialization() 才会触发 getBean(),真正开始加载流程

关键对象与作用

角色 实现类 职责
注册中心 BeanDefinitionRegistry 定义注册/获取BeanDefinition的接口
核心实现 DefaultListableBeanFactory 真正的注册表,持有beanDefinitionMap
定义载体 BeanDefinition 描述Bean的元信息(类名、作用域、依赖、构造器等)
XML读取器 XmlBeanDefinitionReader 解析XML → BeanDefinition
注解读取器 AnnotatedBeanDefinitionReader 处理配置类和@Bean
注解扫描器 ClassPathBeanDefinitionScanner 扫描@Component注解

一句话总结面试回答

Bean注册流程本质是将配置(XML/注解/Java Config)解析成 BeanDefinition 对象,然后存入 DefaultListableBeanFactorybeanDefinitionMap 中。入口是 BeanDefinitionReaderClassPathBeanDefinitionScanner,核心是 BeanDefinitionRegistry.registerBeanDefinition()。注册完成后,由 refresh() 触发的 finishBeanFactoryInitialization() 开始真正的实例化加载流程。

补充:注册 vs 加载 时间线

复制代码
【注册阶段】                      【加载阶段】
                                 
解析配置 → 生成BeanDefinition      实例化对象 → 属性填充 → 初始化
         ↓                                    ↓
存入Map                            调用getBean()创建实例
         ↓                                    ↓
BeanFactoryPostProcessor           BeanPostProcessor
可修改BeanDefinition               可修改/代理Bean实例

注册阶段不创建对象,只是"登记造册"。只有第一次调用 getBean() 或容器 refresh() 完成时,才会真正创建实例。

相关推荐
liangsheng_g12 分钟前
微服务本地开发零配置隔离方案
java·微服务·架构
不服老的小黑哥16 分钟前
六、集合处理(collections.md)
java
IT爱学堂17 分钟前
Go开发疑难杂症终结者通关指南
后端
大勇前进27 分钟前
从10分钟到10秒:一个真实慢查询的SQL Server优化全记录
后端
lisw0528 分钟前
计算与科学哲学(Philosophy of Computing and Science)
java·开发语言·人工智能
站大爷IP28 分钟前
被Python异步坑了三年,才搞懂await和create_task的区别
后端
大白8029 分钟前
你的数据库密码还在用明文?SQL Server 凭据管理的 3 种现代方案
后端
凤山老林29 分钟前
Spring Boot 集成 ShardingSphere-Encrypt 实现字段级实时脱敏
java·spring boot·后端·数据脱敏
vipxieliang29 分钟前
ValidX v1.2.0 更新日志
java·后端
Zane199437 分钟前
只改一个方向的引用,循环引用就能立刻被回收?一文讲透 weakref 弱引用
后端·python