Spring IoC 超清晰讲解:Bean、容器、依赖注入全流程
目录
Spring IOC
一、什么是 IoC?
- 直白点:原来对象的创建、依赖关系要我们自己 new、自己管理;现在交给 Spring 容器来做。
- 控制反转:控制权从“开发者”反转到“容器”。
例如没有 Spring 时:
UserService userService = new UserService(new UserRepository());
我们需要手动 new,自己决定依赖怎么创建。
有了 Spring 后:
UserService userService = context.getBean(UserService.class);
Spring 容器帮我们:
- 创建对象(Bean)
- 解决依赖关系(注入)
- 管理生命周期
二、IoC 的核心:IoC 容器
IoC 容器就是一个“大工厂”,里面存放着各种 Bean,**负责整个 Bean 的生命周期管理。**常见实现:
- BeanFactory:IoC 的最基本容器,按需加载(懒加载)。
- ApplicationContext:BeanFactory 的子接口,功能更强大,支持事件发布、国际化、AOP 等,几乎开发中都是用它。
三、IoC 和 Bean 的关系
- Bean:容器管理的对象(Java 类实例)。
- BeanDefinition:Bean 的“元数据”(配方/蓝图),描述如何创建这个 Bean。
- 类的全限定名
- 作用域(singleton、prototype…)
- 初始化方法、销毁方法
- 依赖关系
容器根据 BeanDefinition 来生产 Bean,就像工厂根据图纸来生产零件。
四、IoC 的依赖注入(DI)
Dependency Injection:对象的依赖不是自己去 new,而是由 Spring 注入。
依赖:一个类需要另外一个类来完成工作,比如:
class UserService {
private UserRepository userRepository; // 依赖
}
UserService 想操作用户,就必须依赖 UserRepository。
注入:这个依赖不是 UserService 自己去 new,而是 Spring 帮你塞进去。
@Service
class UserService {
@Autowired
private UserRepository userRepository; // Spring注入
}
通俗理解:
- 控制反转(IoC) = 你不用自己创建对象,Spring 来管。
- 依赖注入(DI) = Spring 把你需要的依赖塞给你。
常见方式:
-
构造器注入(推荐)
//构造器注入(Spring Boot 下可以省略 @Autowired) @Component public class UserService { private final UserRepository userRepository; @Autowired public UserService(UserRepository userRepository) { this.userRepository = userRepository; } } -
Setter 注入
@Component public class UserService { private UserRepository userRepository; @Autowired public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } } -
字段注入
@Component public class UserService { @Autowired private UserRepository userRepository; }
依赖注入的原理(源码角度)
- 扫描 & 解析 BeanDefinition
@ComponentScan会找到@Component、@Service、@Repository、@Controller标注的类。- 这些类会被解析成 BeanDefinition(保存类信息、依赖信息、作用域等)。
- 创建 Bean
- Spring IOC 容器根据 BeanDefinition 通过反射创建对象。
- 依赖注入(DI)
- Spring 调用
AutowiredAnnotationBeanPostProcessor,解析@Autowired。 - 找到匹配的 Bean(按类型 → 按名称 → @Qualifier → @Primary)。
- 通过反射赋值(字段/构造器/Setter)。
- Spring 调用
依赖查找的顺序:
1. 按类型找(byType)
-
比如你写了:
@Autowired private UserRepository userRepository;Spring 会去 IOC 容器里找 UserRepository 类型的 Bean。
-
如果只有一个,就直接注入。
2. 多个 Bean 时 → 按名称(byName)
-
如果 IOC 里有两个
UserRepository实现,比如:@Repository("userRepo1") class UserRepositoryImpl1 implements UserRepository {} @Repository("userRepo2") class UserRepositoryImpl2 implements UserRepository {}那么 Spring 就会看看 变量名
userRepository,有没有和某个 Bean 的名字匹配。- 如果匹配成功 → 注入对应的 Bean。
- 如果不匹配 → 报错(
NoUniqueBeanDefinitionException)。
3. @Qualifier 指定
-
如果你明确指定了:
@Autowired @Qualifier("userRepo1") private UserRepository userRepository;Spring 就会按照
userRepo1这个名字去注入。
4. @Primary 标记默认
-
你也可以在某个 Bean 上标记:
@Repository @Primary class UserRepositoryImpl1 implements UserRepository {}那么即使有多个同类型的 Bean,Spring 也会默认选这个。
依赖注入的细节
- 按类型注入(默认)
- 如果 IOC 容器中有一个对应类型的 Bean,就直接注入。
- 如果有多个,会报错 → 除非:
@Primary:指定默认首选@Qualifier("beanName"):指定注入哪个
- 循环依赖问题
- Spring 通过 三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)解决了大多数循环依赖。
- 但是 构造器注入无法解决循环依赖。
五、IoC 的好处
- 解耦:对象只关心“需要什么”,不关心“如何得到”。
- 统一管理:Spring 负责对象的创建、初始化、销毁。
- 可扩展:通过配置或注解就能替换实现,而不用改代码。
- 便于测试:可以轻松替换依赖。
总结一句话:
Spring IoC 是一种设计思想,用容器来管理对象和它们的依赖关系,开发者只需要声明需求,容器负责提供和维护。
六、Spring IOC 的加载过程
1. 资源定位(Resource 定位配置文件/注解)
- 容器启动时,先要知道 Bean 的配置来源:
- XML:
<bean>标签 - 注解:
@ComponentScan、@Bean - Java 配置类:
@Configuration
- XML:
- Spring 通过
ResourceLoader找到这些配置文件/类。
2. 解析配置,生成 BeanDefinition
- Spring 使用 BeanDefinitionReader 来解析配置。
- 每一个
<bean>或@Component→ 转换成一个 BeanDefinition 对象。 - BeanDefinition 就是 Bean 的“元信息”(类似于建模),里面存放:
- Bean 的 class 类型
- 作用域(scope)
- 是否懒加载(lazy-init)
- 属性值、依赖信息
- Spring 把这些 BeanDefinition 存到一个 BeanDefinitionMap(ConcurrentHashMap) 里。
- Key = Bean 名称
- Value = BeanDefinition
3. BeanFactoryPostProcessor 阶段(修改 BeanDefinition)
在 BeanDefinition 和 完整BeanDefinition 中间通过一个后置增强器,可以对bean的定义信息进行统一修改,只需要实现 BeanFactoryPostProcessor 接口即可,这个后置增强器是可以有多个的,你只要在不同的类实现多个 BeanFactoryPostProcessor 接口就会执行多次
- 比如:
@ConfigurationProperties就是通过这个阶段注入属性值的。
更多推荐



所有评论(0)