面试官:介绍一下Spring Bean的生命周期和作用域

Spring Bean是Spring框架的核心,理解它的生命周期作用域是面试必考知识点,也是实际开发中避坑的关键。本文用大白话+代码示例,带你轻松掌握这两大核心问题!


一、Spring Bean的生命周期:从出生到销毁

Spring Bean的生命周期可以概括为四大阶段实例化 → 属性赋值 → 初始化 → 销毁。但细节远不止这些,我们通过代码一步步拆解:

1. 实例化(Instantiate)

Spring通过反射调用Bean的构造方法 ,创建一个"原始对象"(此时对象还未填充属性)。
相当于:工厂里造了一辆车的骨架,但还没有装发动机和轮胎。

csharp 复制代码
public class Car {
    public Car() {
        System.out.println("1. 调用构造方法:创建Car实例");
    }
}

2. 属性赋值(Populate Properties)

Spring通过依赖注入(DI) 为Bean的属性赋值(如@Autowired@Value)。
相当于:给车装上发动机、轮胎等零件。

kotlin 复制代码
public class Car {
    @Autowired
    private Engine engine;  // 依赖注入引擎

    public void setEngine(Engine engine) {
        System.out.println("2. 属性赋值:注入Engine");
        this.engine = engine;
    }
}

3. 初始化(Initialize)

这一步是Bean的"成人礼",Spring提供了多种扩展点:

  • BeanPostProcessor接口:在初始化前后插入自定义逻辑。
  • @PostConstruct注解:标记初始化完成后执行的方法。
  • InitializingBean接口 :实现afterPropertiesSet()方法。
typescript 复制代码
public class Car implements InitializingBean {
    @PostConstruct
    public void init() {
        System.out.println("3.1 @PostConstruct:初始化方法");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("3.2 InitializingBean:属性赋值后执行");
    }
}

4. 销毁(Destroy)

Bean使用完毕后,Spring会调用销毁方法(仅适用于单例Bean)。

  • @PreDestroy注解:标记销毁前执行的方法。
  • DisposableBean接口 :实现destroy()方法。
typescript 复制代码
public class Car implements DisposableBean {
    @PreDestroy
    public void preDestroy() {
        System.out.println("4.1 @PreDestroy:销毁前执行");
    }

    @Override
    public void destroy() {
        System.out.println("4.2 DisposableBean:销毁方法");
    }
}

完整生命周期流程图

less 复制代码
构造方法 → @Autowired注入 → BeanPostProcessor前置处理
 → @PostConstruct → InitializingBean → 
BeanPostProcessor后置处理 → ...(使用中)
→ @PreDestroy → DisposableBean

二、Spring Bean的作用域:单例还是原型?

Spring Bean的作用域决定了Bean的创建方式和生命周期,常用作用域有两种:

1. 单例(Singleton)

  • 特点:整个Spring容器中,Bean只有一个实例(默认作用域)。

  • 适用场景:无状态的工具类、服务类(如Service、DAO)。

  • 配置方式

    less 复制代码
    @Scope("singleton")
    @Service
    public class UserService { ... }

2. 原型(Prototype)

  • 特点:每次请求Bean时,都会创建一个新实例。

  • 适用场景:需要保持状态的Bean(如用户购物车)。

  • 配置方式

    less 复制代码
    @Scope("prototype")
    @Component
    public class ShoppingCart { ... }

其他作用域(Web应用专用)

作用域 描述
request 一次HTTP请求创建一个Bean
session 一次用户会话创建一个Bean
application 整个Web应用共享一个Bean

三、常见问题及避坑指南

问题1:单例Bean中注入原型Bean会失效?

现象 :单例Bean中注入的原型Bean只会初始化一次。
原因 :单例Bean在初始化时已经完成依赖注入,后续请求不会重新创建原型Bean。
解决方案 :使用@Lookup注解或ApplicationContext.getBean()手动获取原型Bean。


问题2:@PostConstruct和InitializingBean的执行顺序?

答案@PostConstruct先于InitializingBean执行。
建议 :优先使用@PostConstruct,代码更简洁。


问题3:Bean的生命周期能定制吗?

能! 通过实现以下接口:

  • BeanPostProcessor:干预所有Bean的初始化过程。
  • BeanFactoryPostProcessor:修改Bean的定义信息。

总结

  • 生命周期 :记住四大阶段(实例化 → 属性注入 → 初始化 → 销毁),善用@PostConstruct@PreDestroy
  • 作用域:单例省资源,原型保状态,Web作用域按需选。
  • 避坑:单例中注入原型Bean需特殊处理,避免状态污染。

相关推荐
Bingo_BIG1 天前
Java Spring框架:单表的查询、新增、修改、删除、导入、导出
java·spring·前后端
paopaokaka_luck1 天前
智慧社区综合服务小程序(人脸识别、AI问答、Echarts图形化分析)
前端·javascript·spring boot·spring·数据分析·echarts
牧瀬クリスだ1 天前
YAML配置详解:SpringBoot实战指南
java·spring·yml
需要8262 天前
JVM 内存区域与对象创建:一次 GC 从哪来
java·jvm·spring boot·spring·servlet·tomcat
paopaokaka_luck2 天前
考研政治刷题小程序(AI推荐题目、ECharts数据分析、章节练习与专项训练、模拟考试、错题本与收藏夹、学习打卡与目标管理、题库和组卷维护)
前端·javascript·spring boot·spring·数据分析·echarts
步行cgn2 天前
Spring 基于 XML 的自动装配:byType 详解
java·后端·spring
边境悍匪2 天前
蜗牛学苑 Java 智能体学习 Day46|贯穿项目 2 思维导图复盘
java·开发语言·vue.js·学习·spring
步行cgn2 天前
Spring c 命名空间注入详解
java·后端·spring
需要8262 天前
MySQL 索引 B+ 树与“查询为什么变慢了
java·spring boot·spring·spring cloud·tomcat
vx-程序开发2 天前
【计算机毕设】django校园跑腿服务系统83141
java·数据库·vue.js·spring boot·spring·elasticsearch·django