Spring Bean 的核心五问(作用域、生命周期、工厂模式、实例化、循环依赖)是 Spring 面试/源码阅读中最常被问到的五个核心点。下面按逻辑顺序逐一拆解,带关键源码位置、常见面试追问和代码示例。
1. Spring Bean 的作用域(Scope)有哪些?分别在什么场景使用?
Spring 提供了 7 种标准作用域(其中 5 种最常用):
| 作用域 | 注解 / xml 值 | 创建时机 | 销毁时机 | 典型使用场景 | 是否支持循环依赖 |
|---|---|---|---|---|---|
| singleton | @Scope(“singleton”) | 容器启动时(默认懒加载除外) | 容器关闭时 | 无状态服务(Service、Repository、工具类) | 支持 |
| prototype | @Scope(“prototype”) | 每次 getBean() 时 | 容器不管理销毁 | 有状态对象(每次需要全新实例) | 不支持 |
| request | @Scope(“request”) | 每个 HTTP 请求 | 请求结束 | Web 环境,每个请求一个对象 | 支持 |
| session | @Scope(“session”) | 每个 HTTP Session | Session 失效 | 用户会话级别对象 | 支持 |
| application | @Scope(“application”) | ServletContext 生命周期 | ServletContext 销毁 | 全局应用级别(类似全局变量) | 支持 |
| websocket | @Scope(“websocket”) | WebSocket 会话 | WebSocket 连接关闭 | WebSocket 专用 | 支持 |
| custom | 自定义 Scope | 自定义逻辑 | 自定义逻辑 | 特殊业务场景 | 视实现 |
最常考点:
- 默认是 singleton
- prototype 不支持循环依赖(因为每次 get 都新对象)
- request/session 等需要
RequestContextListener或RequestContextFilter支持
面试追问:如何自定义 Scope?
→ 实现 org.springframework.beans.factory.config.Scope 接口,然后通过 registerScope() 注册。
2. Spring Bean 的完整生命周期(最重要!常考画流程图)
Bean 生命周期大致分为 4 大阶段 + 10+ 个扩展点:
- 实例化前阶段(Instantiation 前)
- BeanDefinition 加载、解析、注册
- BeanFactoryPostProcessor(修改 BeanDefinition)
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() → 可短路返回代理对象
- 实例化阶段(Instantiation)
- 反射调用构造方法(或工厂方法)创建原始对象
- 属性填充阶段(Population)
- InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
- applyPropertyValues → 依赖注入(@Autowired、@Value、xml ref 等)
- Aware 接口回调(BeanNameAware、BeanFactoryAware、ApplicationContextAware 等)
- 初始化阶段(Initialization)
- BeanPostProcessor.postProcessBeforeInitialization()
- InitializingBean.afterPropertiesSet()
- @PostConstruct 注解方法
- BeanPostProcessor.postProcessAfterInitialization() → AOP 代理常在这里生成
- 使用阶段 → 正常使用
- 销毁阶段(Destruction)
- @PreDestroy 注解方法
- DisposableBean.destroy()
- destroy-method(xml 配置)
最经典的 16 步流程(源码:AbstractAutowireCapableBeanFactory.doCreateBean):
BeanDefinition →
1. postProcessBeforeInstantiation
→ 实例化(createBeanInstance)
2. postProcessAfterInstantiation
3. applyPropertyValues(populateBean)→ 依赖注入
4. Aware 接口回调
5. postProcessBeforeInitialization
6. @PostConstruct / afterPropertiesSet
7. postProcessAfterInitialization(AOP 代理在此生成)
→ 放入单例池(addSingleton)
→ 使用
→ 容器关闭
8. @PreDestroy / destroy / destroy-method
常考手撕图(文字版简易流程):
BeanDefinition → Instantiation → 原始对象
↓
填充属性 → 依赖注入(循环依赖关键点)
↓
Aware 接口
↓
BeforeInitialization → @PostConstruct → afterPropertiesSet → AfterInitialization
↓
代理对象(AOP)
↓
放入缓存(单例池)
↓
销毁回调
3. Spring 是如何使用工厂模式的?(BeanFactory vs ApplicationContext)
Spring 大量使用工厂模式,核心是 BeanFactory。
- BeanFactory:最基础的 IoC 容器接口(延迟加载)
- ApplicationContext:高级容器(继承 BeanFactory),预加载、事件发布、国际化等
工厂模式体现:
- BeanFactory 本身就是工厂(getBean 生产 Bean)
- FactoryBean:自定义工厂 Bean(getObject() 返回最终对象)
- 常见:SqlSessionFactoryBean、ProxyFactoryBean
- Bean 工厂方法实例化(xml
<bean factory-method="..."/>或@Bean)
面试常问:FactoryBean 和普通 Bean 区别?
- 普通 Bean:getBean 返回自己
- FactoryBean:getBean 返回
getObject()的结果,&beanName才能拿到 FactoryBean 本身
4. Spring Bean 的实例化方式有哪些?
Spring 支持 4 种主要实例化方式(源码:AbstractAutowireCapableBeanFactory.createBeanInstance):
- 默认构造器实例化(最常见)
- 反射调用无参构造
- 带参构造器实例化(autowire by type / constructor)
- @Autowired 标注构造器
- 静态工厂方法(xml factory-method / @Bean static method)
- 实例工厂方法(xml factory-bean + factory-method)
代码示例:
// 1. 默认构造
@Component
public class UserService {}
// 2. 带参构造
@Component
public class OrderService {
private final UserService userService;
@Autowired
public OrderService(UserService userService) {
this.userService = userService;
}
}
// 3. 静态工厂
@Bean
public static DataSource dataSource() { ... }
// 4. 实例工厂
@Configuration
public class MyFactory {
@Bean
public MyFactoryBean myFactoryBean() {
return new MyFactoryBean();
}
}
public class MyFactoryBean implements FactoryBean<String> {
@Override
public String getObject() { return "hello"; }
}
5. Spring 如何解决循环依赖?(单例 + setter 注入才能解决)
循环依赖分类:
| 类型 | 是否能自动解决 | 解决方式 |
|---|---|---|
| singleton + setter/字段注入 | 是 | 三级缓存 |
| singleton + 构造器注入 | 否 | 抛 BeanCurrentlyInCreationException |
| prototype | 否 | 抛异常 |
| 多例 + 其他 | 否 | — |
三级缓存机制(核心在 DefaultSingletonBeanRegistry):
- singletonObjects(一级缓存):成品 Bean(已完成初始化)
- earlySingletonObjects(二级缓存):早期暴露对象(已实例化,未初始化)
- singletonFactories(三级缓存):ObjectFactory,用于创建早期引用(AOP 代理在此生成)
解决流程(A → B → A):
- A 开始创建 → 实例化(new A) → 放入三级缓存(singletonFactories)
- A 填充属性 → 发现依赖 B → 去 getBean(B)
- B 开始创建 → 实例化(new B) → 放入三级缓存
- B 填充属性 → 发现依赖 A → getBean(A)
- 从三级缓存拿到 A 的 ObjectFactory → getObject() → 得到早期 A(可能已代理) → 放入二级缓存
- B 完成属性填充 → 初始化 → 放入一级缓存
- A 继续 → 拿到 B → 完成初始化 → 放入一级缓存
关键点:
- 只有单例 + 非构造器注入(setter/字段/@Autowired 非构造器)才能解决
- 构造器循环依赖无法解决(因为实例化前就要注入)
- AOP 代理对象在三级缓存 getObject() 时生成
常见破环方式:
- @Lazy(延迟注入代理)
- 改用 setter 注入
- 使用 ObjectProvider / Provider
- 拆分 Bean 或引入中间层
这五个问题是 Spring 容器最核心的原理,基本覆盖了 80% 的面试深度。如果你想深入某一个点(比如三级缓存源码、手写三级缓存、AOP 代理生成时机),可以直接告诉我,我继续带你拆!