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() 完成时,才会真正创建实例。

相关推荐
葫芦和十三18 分钟前
图解 MongoDB 13|WiredTiger 存储引擎:B-tree、页和 checkpoint 三件套
后端·mongodb·agent
葫芦和十三24 分钟前
图解 MongoDB 14|Cache 与淘汰:WiredTiger 的内存治理
后端·mongodb·面试
IT_陈寒4 小时前
Vue这个坑我跳了两次,原来问题出在这
前端·人工智能·后端
人活一口气5 小时前
Spring Boot与AIGC的完美结合:从零搭建智能内容生成平台
java·spring boot·aigc
ServBay5 小时前
9 个 Python 第三方库推荐,不用 AI 都好像多出一个团队
后端·python
用户8356290780515 小时前
如何使用 Python 添加和管理 Excel 批注(完整示例)
后端·python
用户8356290780515 小时前
使用 Python 管理 Excel 工作表:创建、复制、删除与重命名
后端·python
lizhongxuan5 小时前
Agent Tool
后端
CaffeinePro6 小时前
依赖注入:FastAPI最核心的解耦能力案例解析
后端·fastapi
Assby7 小时前
从 Function Calling 到 MCP:理解 Agent 工具调用的底层通信机制
人工智能·后端