依赖注入(Dependency Injection, DI)是Spring框架的核心特性之一,它实现了控制反转(IoC)原则,让对象之间的依赖关系由Spring容器管理,而不是由对象自己创建或查找依赖对象。下面我将详细介绍Spring DI的完整工作过程。
![图片[1]_Spring DI(依赖注入)全过程详解_知途无界](https://zhituwujie.com/wp-content/uploads/2025/09/d2b5ca33bd20250917090010.png)
一、DI基本概念
依赖注入是指容器负责创建对象并管理它们的依赖关系,对象只需要声明它需要什么依赖,而不需要关心这些依赖是如何创建和管理的。
Spring支持三种主要的依赖注入方式:
- 构造器注入(Constructor Injection)
- Setter注入(Setter Injection)
- 字段注入(Field Injection)(通过@Autowired直接标注字段)
二、DI全过程详解
1. 组件扫描与Bean定义
过程:
- Spring容器启动时,会扫描指定的包路径(通过
@ComponentScan注解) - 发现带有
@Component、@Service、@Repository、@Controller等注解的类 - 为这些类创建Bean定义(BeanDefinition),记录类的元数据信息
关键点:
- 这些类将成为Spring管理的Bean
- 容器知道这些类的存在及其依赖关系
2. Bean实例化
过程:
- 当应用需要某个Bean时,Spring容器会根据Bean定义创建该Bean的实例
- 实例化过程通常通过反射调用类的无参构造函数完成
关键点:
- 默认情况下,Bean是单例的(Singleton),即容器中只有一个实例
- 也可以配置为原型(Prototype)、请求(Request)、会话(Session)等作用域
3. 依赖解析与注入
这是DI过程的核心环节,分为以下几个步骤:
(1) 依赖发现
过程:
- Spring分析Bean的构造函数、setter方法或字段,寻找需要注入的依赖
- 通过注解(如
@Autowired、@Resource、@Inject)或配置确定依赖关系
注入方式分析:
- 构造器注入:通过类的构造函数参数识别依赖
- Setter注入:通过setter方法参数识别依赖
- 字段注入:直接通过字段识别依赖(不推荐)
(2) 依赖查找
过程:
- 对于每个发现的依赖,Spring在容器中查找匹配的Bean
- 查找过程考虑Bean的类型和限定符(如
@Qualifier指定的值) - 如果找到多个同类型Bean,需要通过
@Primary或@Qualifier解决歧义
关键点:
- Spring首先尝试按类型匹配
- 如果按类型找到多个Bean,则按名称匹配或使用限定符
(3) 依赖注入
过程:
- 找到匹配的依赖Bean后,Spring将其注入到目标Bean中
- 注入方式取决于注入类型:
- 构造器注入:通过反射调用构造函数并传入依赖
- Setter注入:通过反射调用setter方法设置依赖
- 字段注入:通过反射直接设置字段值
关键点:
- 注入过程是递归的,如果依赖的Bean本身也有依赖,Spring会先解析这些依赖
- 整个过程形成了一个依赖关系图,Spring确保依赖关系正确解析
4. 初始化与后处理
过程:
- 依赖注入完成后,Spring会调用Bean的初始化方法
- 可以通过
@PostConstruct注解、实现InitializingBean接口或配置init-method指定初始化方法
后处理器作用:
- Spring的Bean后处理器(BeanPostProcessor)在此阶段可以对Bean进行额外处理
- 例如:AOP代理创建、属性填充等
5. Bean就绪可用
过程:
- 经过上述所有步骤后,Bean完全初始化并准备好被使用
- 当应用代码请求该Bean时,Spring直接返回已创建并注入依赖的实例
三、DI工作过程详细流程图
Spring容器启动
│
├── 扫描包路径,发现@Component等注解的类
│ │
│ └── 为每个类创建Bean定义(BeanDefinition)
│
└── 准备Bean工厂,等待Bean请求
│
└── 当应用请求某个Bean时
│
├── 1. 实例化Bean(通常通过无参构造函数)
│
├── 2. 依赖解析与注入
│ │
│ ├── 2.1 依赖发现(分析构造器/方法/字段)
│ │
│ ├── 2.2 依赖查找(在容器中查找匹配Bean)
│ │ │
│ │ └── 考虑类型、限定符、@Primary等
│ │
│ └── 2.3 依赖注入(通过反射设置依赖)
│ │
│ ├── 构造器注入(通过构造函数)
│ ├── Setter注入(通过setter方法)
│ └── 字段注入(直接设置字段值)
│
├── 3. 初始化Bean
│ │
│ ├── 调用@PostConstruct方法
│ ├── 调用InitializingBean.afterPropertiesSet()
│ └── 调用配置的init-method方法
│
└── 4. Bean就绪可用(可被应用代码使用)
四、DI过程的关键组件
1. BeanFactory
Spring容器的核心接口,负责Bean的创建、配置和管理。ApplicationContext是BeanFactory的高级扩展。
2. BeanDefinition
包含Bean的元数据信息,如类名、作用域、构造函数参数、属性值等。Spring根据BeanDefinition创建实际的Bean实例。
3. BeanPostProcessor
Bean后处理器接口,允许在Bean初始化前后进行自定义处理,是实现AOP、属性编辑器等功能的基础。
4. AutowiredAnnotationBeanPostProcessor
专门处理@Autowired和@Value注解的后处理器,是实现自动注入的关键组件。
五、DI过程优化与扩展
1. 延迟初始化
通过@Lazy注解或配置,可以让Bean在首次使用时才创建,提高启动性能。
2. 条件化Bean创建
通过@Conditional注解,可以根据条件决定是否创建某个Bean。
3. Bean作用域管理
除了单例(Singleton)外,还可以配置原型(Prototype)、请求(Request)、会话(Session)等不同作用域的Bean。
4. Profile-specific Bean
通过@Profile注解,可以为不同环境(如dev、test、prod)配置不同的Bean实现。
六、最佳实践
- 优先使用构造器注入:特别是对于强制依赖,构造器注入更明确且利于不可变对象创建
- 合理使用Setter注入:对于可选依赖,Setter注入更灵活
- 避免字段注入:虽然方便,但降低了代码的可测试性和明确性
- 明确依赖关系:使用
@Qualifier解决多实现类的歧义问题 - 利用Spring Boot自动配置:在Spring Boot中,大量使用约定优于配置的原则简化DI配置
通过理解Spring DI的完整过程,开发者可以更好地利用Spring框架的强大功能,编写更清晰、更可维护的应用程序代码。

























暂无评论内容