Spring Bean 核心五问:作用域、生命周期、工厂模式、实例化与循环依赖

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 SessionSession 失效用户会话级别对象支持
application@Scope(“application”)ServletContext 生命周期ServletContext 销毁全局应用级别(类似全局变量)支持
websocket@Scope(“websocket”)WebSocket 会话WebSocket 连接关闭WebSocket 专用支持
custom自定义 Scope自定义逻辑自定义逻辑特殊业务场景视实现

最常考点

  • 默认是 singleton
  • prototype 不支持循环依赖(因为每次 get 都新对象)
  • request/session 等需要 RequestContextListenerRequestContextFilter 支持

面试追问:如何自定义 Scope?
→ 实现 org.springframework.beans.factory.config.Scope 接口,然后通过 registerScope() 注册。

2. Spring Bean 的完整生命周期(最重要!常考画流程图)

Bean 生命周期大致分为 4 大阶段 + 10+ 个扩展点

  1. 实例化前阶段(Instantiation 前)
  • BeanDefinition 加载、解析、注册
  • BeanFactoryPostProcessor(修改 BeanDefinition)
  • InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() → 可短路返回代理对象
  1. 实例化阶段(Instantiation)
  • 反射调用构造方法(或工厂方法)创建原始对象
  1. 属性填充阶段(Population)
  • InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
  • applyPropertyValues → 依赖注入(@Autowired、@Value、xml ref 等)
  • Aware 接口回调(BeanNameAware、BeanFactoryAware、ApplicationContextAware 等)
  1. 初始化阶段(Initialization)
  • BeanPostProcessor.postProcessBeforeInitialization()
  • InitializingBean.afterPropertiesSet()
  • @PostConstruct 注解方法
  • BeanPostProcessor.postProcessAfterInitialization() → AOP 代理常在这里生成
  1. 使用阶段 → 正常使用
  2. 销毁阶段(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),预加载、事件发布、国际化等

工厂模式体现

  1. BeanFactory 本身就是工厂(getBean 生产 Bean)
  2. FactoryBean:自定义工厂 Bean(getObject() 返回最终对象)
  • 常见:SqlSessionFactoryBean、ProxyFactoryBean
  1. Bean 工厂方法实例化(xml <bean factory-method="..."/>@Bean

面试常问:FactoryBean 和普通 Bean 区别?

  • 普通 Bean:getBean 返回自己
  • FactoryBean:getBean 返回 getObject() 的结果,&beanName 才能拿到 FactoryBean 本身

4. Spring Bean 的实例化方式有哪些?

Spring 支持 4 种主要实例化方式(源码:AbstractAutowireCapableBeanFactory.createBeanInstance):

  1. 默认构造器实例化(最常见)
  • 反射调用无参构造
  1. 带参构造器实例化(autowire by type / constructor)
  • @Autowired 标注构造器
  1. 静态工厂方法(xml factory-method / @Bean static method)
  2. 实例工厂方法(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):

  1. singletonObjects(一级缓存):成品 Bean(已完成初始化)
  2. earlySingletonObjects(二级缓存):早期暴露对象(已实例化,未初始化)
  3. singletonFactories(三级缓存):ObjectFactory,用于创建早期引用(AOP 代理在此生成)

解决流程(A → B → A):

  1. A 开始创建 → 实例化(new A) → 放入三级缓存(singletonFactories)
  2. A 填充属性 → 发现依赖 B → 去 getBean(B)
  3. B 开始创建 → 实例化(new B) → 放入三级缓存
  4. B 填充属性 → 发现依赖 A → getBean(A)
  5. 从三级缓存拿到 A 的 ObjectFactory → getObject() → 得到早期 A(可能已代理) → 放入二级缓存
  6. B 完成属性填充 → 初始化 → 放入一级缓存
  7. A 继续 → 拿到 B → 完成初始化 → 放入一级缓存

关键点

  • 只有单例 + 非构造器注入(setter/字段/@Autowired 非构造器)才能解决
  • 构造器循环依赖无法解决(因为实例化前就要注入)
  • AOP 代理对象在三级缓存 getObject() 时生成

常见破环方式

  • @Lazy(延迟注入代理)
  • 改用 setter 注入
  • 使用 ObjectProvider / Provider
  • 拆分 Bean 或引入中间层

这五个问题是 Spring 容器最核心的原理,基本覆盖了 80% 的面试深度。如果你想深入某一个点(比如三级缓存源码、手写三级缓存、AOP 代理生成时机),可以直接告诉我,我继续带你拆!

文章已创建 4631

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部