前言
做Java开发的同学,谁还没被Spring IOC的核心知识点拷打过?不管是校招入门,还是社招进阶,ApplicationContext和BeanFactory的区别、Bean的5大作用域、Bean生命周期,这仨绝对是面试出场率99%的高频考点。
很多同学背了又忘,忘了又背,一到面试要么答不全,要么被面试官追问到哑口无言。今天这篇文章,我就用最通俗的话,结合代码案例,把这三个知识点扒得明明白白,不仅让你记住,还让你懂原理、知场景,面试直接把满分答案甩出来!
一、ApplicationContext和BeanFactory,谁才是Spring容器的真·核心?
首先要明确:Spring的灵魂是IOC容器,而BeanFactory和ApplicationContext,就是IOC容器最核心的两个接口,很多新手刚学的时候直接把他俩混为一谈,这可就大错特错了!
1. 先搞懂他俩的"辈分":实打实的父子关系
-
BeanFactory :Spring框架最顶层的核心接口,是所有Spring容器的"老祖宗"。它定义了IOC容器最基础、最核心的能力------Bean的获取、生命周期管理等,你可以把它理解成Spring容器的极简裸机版,只保留了最核心的容器功能。
-
ApplicationContext :它是BeanFactory的子接口,100%继承了BeanFactory的所有能力,并且在其基础上做了大量企业级扩展增强。相当于在裸机上装了全套系统和生态软件,是Spring的豪华旗舰版容器。
2. 核心区别:懒加载VS预加载(面试核心得分点)
这是两者最本质的区别,也是面试必问的核心,我直接整理成对比表,一眼看懂:
| 核心特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 接口层级 | IOC顶级父接口 | BeanFactory的子接口,功能更全面 |
| Bean创建时机 | 懒加载:只有调用getBean()、真正要使用这个Bean时,才会创建实例 | 预加载(饿汉式):容器启动加载配置文件时,就会把所有单例Bean一次性创建完成,存入容器 |
| 扩展能力 | 仅提供核心的Bean管理能力 | 额外提供国际化处理、事件发布机制、资源加载、AOP无缝集成、环境变量处理等企业级功能 |
| 适用场景 | 资源受限的嵌入式开发、移动端等对内存要求极高的场景 | 绝大多数Java企业级开发,我们日常项目中用的基本都是ApplicationContext |
3. 面试点睛答题话术
很多同学只答了创建时机的区别,面试官一追问就懵了,记住这个满分答题模板:
BeanFactory是Spring IOC的顶级核心接口,定义了容器最基础的Bean管理能力,采用懒加载机制,只有使用Bean时才会完成实例化;而ApplicationContext是它的子接口,完整继承了全部核心功能,默认采用预加载机制,容器启动就完成单例Bean的创建,同时还提供了国际化、事件发布、资源加载等企业级扩展能力,是企业开发中的首选。
二、Spring Bean的5大作用域,别再只会说单例和多例了!
面试时一被问Bean的作用域,很多同学张口就来singleton和prototype,再问就没了,这直接就丢分了!Spring官方定义了5个标准的Bean作用域,今天一次性给你讲全、讲透。
1. 5大作用域全解析
先划重点:5个作用域里,singleton和prototype在普通Java项目中即可使用,剩下3个仅在Web Spring MVC环境下生效,千万别搞混了!
(1)singleton:单例模式(Spring默认作用域)
这是我们日常开发中用得最多的作用域,也是Spring的默认选择。
-
核心特性:整个IOC容器中,这个Bean只会创建唯一一个实例,所有获取该Bean的请求,返回的都是同一个对象。
-
底层实现:Spring会把创建好的单例Bean,放到名为singletonObjects的Map(也就是大家常说的Spring一级缓存)中,每次使用直接从Map里取,无需重复创建。
-
配置方式:
XML配置:<bean id="userService" class="com.hg.service.impl.UserServiceImpl" scope="singleton"/>
注解配置:@Scope("singleton") (不写scope默认就是单例)
(2)prototype:多例模式
-
核心特性:每次从容器中获取这个Bean,都会创建一个全新的实例,相当于每次都执行一次new操作。
-
底层实现:不会存入单例缓存Map,每次调用getBean都会通过反射调用newInstance()创建新对象。
-
配置方式:
XML配置:<bean id="userService" class="com.hg.service.impl.UserServiceImpl" scope="prototype"/>
注解配置:@Scope("prototype")
(3)request:请求域
-
核心特性:仅Web环境生效,在一次HTTP请求的完整生命周期内,只会创建一个Bean实例,不同HTTP请求会创建完全独立的实例。
-
适用场景:单次请求内共享的对象,比如请求参数封装、请求链路追踪对象。
(4)session:会话域
-
核心特性:仅Web环境生效,在一个用户会话(Session)的生命周期内,只会创建一个Bean实例,不同用户的会话互不影响。
-
适用场景:用户会话信息、登录用户信息存储等。
(5)application:全局应用域
-
核心特性:仅Web环境生效,在整个Web应用的生命周期内,只会创建一个Bean实例,数据存放在ServletContext中,全应用共享。
-
适用场景:应用全局的配置信息、全局计数器等。
2. 面试必追问:单例和多例,到底该怎么选?
光背定义没用,面试官更关心你会不会用,这两个作用域的选型,记住一个核心原则:无状态用单例,有状态用多例。
- 单例singleton首选场景:无状态的Bean,也就是Bean里的成员属性不会被修改,多线程调用不会产生线程安全问题。
典型场景:Dao层、Service层、Controller层的Bean,还有各种工厂对象(SqlSessionFactory、DataSource),这些对象我们只用来调用方法,不会修改其内部属性,用单例能大幅减少对象创建销毁的开销,提升性能。
- 多例prototype必用场景:有状态的Bean,也就是Bean里有可修改的成员属性,多线程环境下会出现线程安全问题。
典型场景:数据库连接Connection、Mybatis的SqlSession、业务实体封装对象,这些对象每次使用都需要独立的状态,必须用多例,否则会出现严重的数据错乱问题。
3. 新手必避坑
单例Bean里注入多例Bean,会出现多例失效的问题!因为单例Bean只在容器启动时创建一次,依赖注入也只会执行一次,就算你注入的是多例Bean,也只会被注入一次,后续不会再更新新的实例。这个坑大家一定要提前规避!
三、Spring Bean生命周期,背了就忘?看完再也忘不了!
Bean的生命周期,绝对是Spring面试的"老大难",很多同学死记硬背步骤,结果面试一紧张就顺序全乱了。今天我就结合大家最熟悉的代码案例,把生命周期拆解得明明白白,还会讲清单例和多例Bean生命周期的天差地别!
1. 先上代码案例,眼见为实
我们先写一个简单的Bean,把生命周期的每个关键节点都打上日志,直观看到执行顺序:
对应的XML配置,指定初始化和销毁方法:
2. 核心结论:单例Bean VS 多例Bean,生命周期完全不一样!
很多同学背生命周期,连单例和多例的区别都没搞懂,那肯定背不对!这俩的执行时机、销毁逻辑,完全是两码事。
(1)单例Bean(singleton,默认)的完整生命周期
单例Bean的命运,完全由Spring容器掌控,从容器启动"出生",到容器关闭"死亡",全程都在容器的管控之中。
完整执行流程:
【启动Spring容器】 → 1. 调用构造方法(实例化Bean) → 2. 调用set方法(依赖注入,给属性赋值) → 3. 调用init初始化方法(Bean自定义初始化) → 【Bean可以正常使用了】 → 【关闭Spring容器】 → 4. 调用destroy销毁方法(执行资源释放)
一句话总结:容器启动就出生,容器关闭才销毁,生命周期全程归Spring管。
(2)多例Bean(prototype)的完整生命周期
多例Bean就不一样了,Spring只管"生",不管"养",更不管"死"!
完整执行流程:
【调用getBean()获取Bean,也就是使用对象时】 → 1. 调用构造方法(实例化Bean) → 2. 调用set方法(依赖注入) → 3. 调用init初始化方法 → 【Bean交给调用者,Spring就不再管控了】 → 【JVM垃圾回收,对象无引用可达】 → 4. 调用destroy销毁方法
划重点:Spring创建完多例Bean交给调用者后,就再也不管理这个对象了,不会主动调用destroy方法,只能靠JVM的垃圾回收机制完成销毁。
3. 面试点睛
答题的时候,一定要先分清单例和多例的核心区别,再讲完整的生命周期步骤,不要上来就瞎背步骤,不然面试官一句"多例Bean也是这样吗?",你直接就懵了。
总结
今天这篇文章,把Spring IOC最核心的三个面试考点全给大家讲透了:
-
BeanFactory和ApplicationContext的父子关系、核心区别,以及面试满分答题话术;
-
Bean的5大作用域,每个的特性、适用场景,以及单例多例的选型原则;
-
Bean的完整生命周期,单例和多例的核心差异,再也不用死记硬背。
这些知识点,不仅是面试必问,更是我们日常开发中排查问题、正确使用Spring的基础,理解了原理,才能少踩坑。