Bean是什么?
Bean 就是 Spring IOC 容器管理的对象,交给 Spring 创建、装配、生命周期管理的 Java 对象就叫 Bean;自己new出来的对象不属于 Spring Bean。
如何定义 Bean?(三种配置方式)
Spring 提供三种方式来声明 Bean,现在企业开发中注解驱动是主流:
方式 | 适用场景 | 示例 |
XML 配置(老旧) | 遗留系统维护,或需要引入第三方无法改源码的类 | <bean id="userDao" class="com.dao.UserDao"/> |
注解定义(最常用) | 自己编写的类,直接在类上加注解 | @Component、@Service、@Repository、@Controller |
Java 配置类(推荐) | 第三方类或需要复杂构造逻辑的 Bean | @Configuration + @Bean 写在方法上 |
@Component 和 @Bean 区别
@Component:打在类上,适合自己写的业务类;由组件扫描自动发现。
@Bean:打在配置类的方法上;适合第三方组件,类源码不能修改,无法加 @Component。
Bean 的作用域 scope
Spring 默认是 单例(Singleton)。
作用域 | 含义 | 适用场景 |
singleton(默认) | 整个 IoC 容器中只有一个实例,所有地方共用。 | 无状态的 Service、Dao(绝大多数业务场景)。 |
prototype | 每次从容器中 getBean() 或注入时,都新建一个实例。 | 有状态的对象(如每次请求参数不同的实体)。 |
request | 仅对当前 HTTP 请求有效,每个请求新建一个。 | Web 层,如当前登录用户信息对象。 |
session | 仅对当前 HTTP Session 有效。 | 用户会话级别的购物车对象。 |
Bean 完整生命周期
解析配置:扫描类,生成 BeanDefinition
实例化:反射调用构造方法,new 出空对象(此时属性还没赋值)
依赖注入 DI:给属性赋值,装配 @Autowired 依赖
Aware 接口回调:BeanNameAware、ApplicationContextAware,把容器 /beanName 注入给 bean
初始化阶段
① @PostConstruct 注解方法 ② InitializingBean#afterPropertiesSet() ③ @Bean(initMethod = "xxx") 指定初始化方法
Bean 就绪,可以给业务使用
容器关闭销毁 ① @PreDestroy ② DisposableBean#destroy() ③ @Bean(destroyMethod="xxx")
BeanDefinition
↓
实例化
↓
属性注入
↓
Aware 回调
↓
BeanPostProcessor
↓
初始化
↓
BeanPostProcessor
↓
Bean 可以使用
↓
容器关闭
↓
销毁
解决一个经典难题:循环依赖(三级缓存)
如果是单例 Bean,Spring 能解决 Setter 注入造成的循环依赖(如 A 依赖 B,B 依赖 A)。它利用的是三级缓存(singletonFactories),在对象实例化后、属性填充前,先把“半成品对象”提前曝光出来,从而打破闭环。
一级缓存 `singletonObjects`:完全初始化完毕的 Bean
二级缓存 `earlySingletonObjects`:实例化完成,但还没填充属性的对象,避免重复执行代理
三级缓存 `singletonFactories`:lambda 工厂,提前暴露对象引用,有可能生成代理对象
注意:构造器注入的循环依赖无法解决,Spring 会直接报错。因此,官方推荐使用 Setter 注入或字段注入来规避构造器循环依赖。