Spring面试25题考点全拆解:IoC容器、Bean生命周期与自动装配

发布时间:2026/10/24 22:01:58
Spring面试25题考点全拆解:IoC容器、Bean生命周期与自动装配

简介:经典的Spring面试问答合集,面向Java开发者和准备技术岗位面试的求职者,聚焦Spring框架的核心知识与常见高频考点。内容覆盖IoC与依赖注入的理解、BeanFactory与ApplicationContext的区别、Bean的生命周期与作用范围、XML/Java/注解三种配置方式、构造器注入与setter注入的对比,以及@Required、@Autowired、@Qualifier等注解的实际用法,适合用来在面试前系统梳理和查漏补缺。资料为单个docx文档,压缩包内共1个文件,体积约88KB,轻便易存;文档以问答题形式呈现,整理了25个代表性的Spring面试问题,并附带解答示例和要点说明,例如单例Bean是否线程安全、如何注入集合类与Properties、FileSystemResource与ClassPathResource的区别、Spring中使用的设计模式总结等。这些内容既能帮助理解Spring容器的工作原理,也能为实际项目中的配置和开发提供参考。目前已有403人学习过该资料,是不少开发者面试准备阶段的选用材料。通过这份问答清单,读者可以快速明确Spring面试的考察方向,补齐概念盲区,提高复习效率。

1. 先搞懂 Spring 面试考什么:25 道经典题背后的考点分布

Spring 面试题看着是考察框架知识,实际上考的是你区分「会用」和「懂原理」的能力。常见的翻车现场是:背了一堆配置标签,却被一句「BeanFactory 和 ApplicationContext 有什么区别」问住;准备了 Spring Boot 项目细节,却被「Spring Bean 的生命周期怎么管理」问得卡壳。翻看这份经典 25 题清单,它的重心根本不是代码量,而是一层层追问容器、Bean、装配、注解这些核心机制。你不需要会写多复杂的 Spring 应用,但必须能把 IoC、DI、生命周期、作用域、自动装配这些概念讲清楚,并且能配合项目里真实用到的注解和配置方式展开。这份资源对你最大的价值,是把 Spring 面试中反复出现的考点压缩成可背诵的问答清单,照着过一遍,就能覆盖大部分技术面的一二轮考察。

2. IoC 与 DI 高频考点:控制反转、依赖注入与容器接口怎么答

2.1 控制反转和依赖注入的本质区别

很多人在面试时把 IoC 和 DI 当成同一个东西回答,这是最常见的失分点。控制反转(IoC)是一种设计思想,核心是把对象之间的耦合关系从「程序内部写死」转移到「容器运行时组装」;依赖注入(DI)则是实现这种思想的具体手段。面试官问到「什么是依赖注入」时,最想听到的是你分得清这两个层次,而不是只有一句「不用 new 对象了」。

依赖注入在 Java 中主要有三种实现方式:构造器注入、Setter 方法注入、接口注入。构造器注入在对象创建时就要把依赖传进去,适合必填依赖;Setter 注入则可以在对象创建后再补充依赖,适合可选依赖。答题时可以补一句:控制反转关注的是「谁控制谁、控制什么」,依赖注入关注的是「怎么把依赖送进去」。这句点题的话,能让面试官觉得你是真的理解而不是背了面经。

2.2 Spring 中 IoC 容器的作用:从 BeanFactory 到 ApplicationContext

Spring 的 IoC 容器由 org.springframework.beans 包和 org.springframework.context 包构成基础。BeanFactory 接口提供了先进的配置机制,是 IoC 容器的核心接口,各种 bean 的定义、实例化和关联关系的建立都由它来管理。ApplicationContext 是 BeanFactory 的子接口,在 BeanFactory 的功能之上增加了国际化文本消息处理、统一的资源文件读取方式、事件传播,以及针对 Web 应用的应用层配置。

面试问到「Spring IoC 容器如何工作」,你可以按这条链路回答:容器读取配置(XML、注解或 Java 配置类)→ 注册 bean 定义 → 根据定义实例化 bean → 通过构造器或 setter 完成依赖注入 → 将可用 bean 存入容器供客户端获取。这类题通常这么答比较稳妥:先说明容器本质是管理 bean 的工厂,再点出 BeanFactory 与 ApplicationContext 的扩展关系,最后把「实例化、配置、组装」三步讲完整。

2.3 BeanFactory 和 ApplicationContext 的区别:一道必考对比题

BeanFactory 可以理解为含有一组 bean 定义的工厂类,在接收到客户端请求时才实例化对应的 bean;ApplicationContext 在包含全部 bean 定义和关联关系设置的基础上,额外提供了对国际化的支持、统一的资源文件读取方式,以及在监听器中注册 bean 的事件机制。常见的三种 ApplicationContext 实现类是 ClassPathXmlApplicationContext、FileSystemXmlApplicationContext 和 XmlWebApplicationContext。

面试遇到「BeanFactory 和 ApplicationContext 有什么区别」时,建议从四个维度展开:功能范围、加载时机、Web 支持、事件与国际化。加载时机这道题最容易踩坑,很多人误以为 ApplicationContext 启动时会把所有 bean 都加载完,严格说它默认是预加载单例 bean,而 BeanFactory 是懒加载。补上一句「在实际项目中绝大多数使用的是 ApplicationContext 系列,BeanFactory 更多作为底层容器接口出现」,答案就完整了。

3. Bean 生命周期与作用域高频题:容器如何造 Bean、管 Bean、销毁 Bean

3.1 Bean 生命周期的四种管理方式

Spring Bean 的生命周期管理是面试官的黄金追问区,几乎每个面试者在自我介绍提到 Spring 后都会被问到。Bean 在被实例化后需要执行一系列初始化操作才能进入可用状态;当不再被调用时,需要执行相关析构操作并从容器中移除。BeanFactory 负责管理容器中创建的 bean 的生命周期,生命周期由两组回调方法组成:初始化之后调用的回调方法、销毁之前调用的回调方法。

Spring 框架提供四种方式管理生命周期事件:实现 InitializingBean 和 DisposableBean 回调接口;实现针对特殊行为的 Aware 接口;在 Bean 配置文件中指定自定义的 init 方法和 destroy 方法;使用 @PostConstruct 和 @PreDestroy 注解。其中 XML 方式最直观,在 标签中通过 init-method 和 destroy-method 属性指定自定义方法,比如配置 demoBean 时声明 customInit 和 customDestroy。

面试答题建议按执行顺序来:先讲 @PostConstruct 注解方法和自定义 init 方法谁先谁后,再提 InitializingBean 的 afterPropertiesSet 方法,最后补充销毁阶段的 @PreDestroy 与 DisposableBean 的 destroy 方法。这里有个常见的记忆技巧:注解优先于接口方法、接口方法优先于配置方法。把顺序讲清楚,比单纯背四种方式名称更容易让面试官认可。

3.2 五种 Bean 作用域对比:从 singleton 到 global-session

Spring 容器中的 bean 有五种作用域:singleton 是默认范围,保证每个容器中只有一个实例,由 BeanFactory 自身维护单例模式;prototype 与原形范围相反,为每一个请求提供一个新实例;request 为每一个来自客户端的网络请求创建一个实例,请求完成后被垃圾回收器回收;session 确保每个 session 中有一个 bean 实例,session 过期后 bean 随之失效;global-session 与 Portlet 应用相关,在部署到 Portlet 容器时用于所有 portlet 共享的全局存储变量。

面试最常考察的对比是 singleton 和 prototype。singleton 适合无状态的服务类、DAO 类、工具类;prototype 适合有状态的场景,比如视图模型对象和包含可变状态的业务对象。request 和 session 更多地出现在 Web 应用上下文中。答作用域题时建议补一句「作用域决定 bean 实例的存活范围,与生命周期回调共同构成容器对 bean 的管控」,能把两道题串起来。

这部分可以结合一个面试场景练习:面试官问「一个用户登录状态存储对象应该用什么作用域」,不要回答 singleton,也不要回答 request,标准思路是 session 作用域,因为登录状态要求整个会话期间共享,会话结束才销毁。这类场景题考的不是记忆,而是对作用域含义的理解。

3.3 单例 Bean 是否线程安全:一道容易答绝对化的题

Spring 框架并没有对单例 bean 做任何多线程封装处理,单例 bean 的线程安全和并发问题需要开发者自行解决。这个点是面试的高频陷阱:不少人直接回答「Spring 单例是线程安全的」,这句话本身就是错的。正确的表述是:大部分 Spring 单例 bean 不包含可变状态,例如 Service 类和 DAO 类,它们天然是线程安全的;但一旦 bean 中包含可变实例变量,比如视图模型对象,就需要自行保证线程安全。

最简单的解决办法是把多态 bean 的作用域由 singleton 变更为 prototype。更进一步可以这样展开:如果 bean 有可变状态,可以考虑把状态抽取到独立对象中,或者使用 ThreadLocal 保存状态,或者对关键操作加锁。面试官最想听的不是你背出的方案列表,而是你能意识到「框架没有替你管并发」这个事实,并且能给出自己的取舍思路。

3.4 内部 Bean、事件机制与资源读取:容易被忽略的武器

内部 bean 是这道清单里容易被轻视的考点。当一个 bean 只被另一个 bean 的某个属性使用时,最合理的做法是把它声明为内部 bean,通过 setter 注入属性或构造方法注入构造参数来实现。输入里的例子很典型:Customer 类引用 Person 类,此时只需创建 Person 实例并在 Customer 内部使用,不必单独暴露这个 bean。

Spring 事件机制也是一个潜在考点。ApplicationContext 支持事件传播,当容器中发生事件时,注册在监听器中的 bean 可以接收到事件通知。回答事件题时先讲三个角色:事件源、事件、监听器,再补充 ApplicationEvent 与 ApplicationListener 对应的关系。

FileSystemResource 和 ClassPathResource 的对比同样值得留意。FileSystemResource 从文件系统路径读取资源,依赖于程序运行的当前目录;ClassPathResource 从类路径读取资源,项目打包成 jar 后依然能正常读取。实际开发中更常用 ClassPathResource,因为它不依赖外部文件系统环境。答题时点出「配置文件随包走」这个经验判断,会给面试官留下实际项目经验的印象。

4. 配置方式与装配实战:XML、Java、注解三选一,集合注入与自动装配

4.1 三种配置方式的选择策略:基于 XML、基于注解、基于 Java

Spring 支持三种配置方式:基于 XML 的配置、基于注解的配置、基于 Java 的配置。面试官问「Spring 有几种配置方式」,你需要答出这三种,并说明各自的适用场景。XML 配置把所有组件以 XML 文件形式统一管理,优点是集中、直观,缺点是配置文件冗长;注解配置把 bean 描述转移到组件类内部,在相关类、方法或字段声明上使用注解即可,代码更紧凑;Java 配置使用 @Configuration 和 @Bean 注解,完全摆脱 XML,适合新项目。

基于注解的配置在 Spring 2.5 之后开始支持,可以用注解替代 XML 方式描述 bean。需要注意一点:注解注入会被容器在 XML 注入之前处理,也就是说 XML 配置会覆盖注解对同一属性的处理结果。注解装配在 Spring 中默认是关闭的,需要在配置文件中添加 context:annotation-config/ 标签才能开启。这在面试中是个高频细节,答错就容易暴露知识盲区。

4.2 基于 XML 的配置与 Web 场景:一个完整实例

基于 XML 的配置是 Spring 最经典的接入方式。配置文件以 开头,包含一系列的 bean 定义和专门的应用配置选项。Spring XML 配置的主要目的是使所有 Spring 组件都能用 XML 文件形式进行配置,依靠 Spring 命名空间的 XML 标签实现,主要命名空间包括 context、beans、jdbc、tx、aop、mvc 和 aso。一个简单的 XML 片段可以这样描述 bean:

<beans> <bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/> <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/> </beans>

这里配置了视图解析器和 JSON 模板两个 bean。BeanNameViewResolver 负责将视图名解析为 Spring 管理的 bean,MappingJackson2JsonView 用于把模型数据输出为 JSON 格式。在 Web 应用中,web.xml 只需配置 DispatcherServlet 即可满足运行时组件的需求:

<web-app> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>

这段配置的核心是 DispatcherServlet 与 URL 映射:所有请求都会进入名为 spring 的 DispatcherServlet,交给 Spring MVC 框架处理。面试如果让手写 Spring MVC 入口配置,只需要达到这个程度就能过关。注意 Servlet 类的全限定名要写完整,同时设置 load-on-startup 让容器启动时提前初始化,避免第一个请求才触发加载带来延迟。

4.3 基于 Java 的配置:@Configuration 与 @Bean 的配合

基于 Java 的配置由 @Configuration 和 @Bean 两个注解支撑。被 @Configuration 注解的类表示其主要职责是作为 bean 定义的资源;由 @Bean 注解的方法负责实例化、配置和初始化一个新对象,交由 Spring 的 IoC 容器管理,作用与 元素类似。一个简单的 Java 配置类如下:

@Configuration public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }

这段代码等价于 XML 中的 。@Configuration 类内部的方法之间可以直接互相调用,用来设置嵌入 bean 的依赖关系。要使用组件扫描,则加上 @ComponentScan(basePackages = "com.example"),容器扫描指定包路径下被 @Component 声明的类,找到后注册为 bean。

实例化这种配置的方式使用 AnnotationConfigApplicationContext 类:

public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); }

getBean 方法按类型从容器中获取已经完成初始化和依赖注入的实例。这个例子展示了纯 Java 配置的完整链路:配置类 → 容器加载 → 获取 bean → 调用业务方法。如果是在 Web 应用中使用这种配置,需要改用 AnnotationConfigWebApplicationContext,配合 ContextLoaderListener 和 DispatcherServlet 完成初始化。答题时强调「@Bean 负责定义,@ComponentScan 负责发现,AnnotationConfigApplicationContext 负责启动」这个分工,思路会更清楚。

4.4 集合注入与 Properties 注入:XML 配置的四个标签

Spring 提供了四种集合类的配置元素: 装配可重复的 list 值,装配没有重复的 set 值,注入键和值可以是任意类型的键值对, 注入键和值都是字符串类型的键值对。一个集合注入的 XML 片段如下:

<beans> <bean id="javaCollection" class="com.example.JavaCollection"> <property name="customList"> <list> <value>INDIA</value> <value>USA</value> <value>UK</value> </list> </property> <property name="customSet"> <set> <value>INDIA</value> <value>USA</value> <value>UK</value> </set> </property> <property name="customMap"> <map> <entry key="1" value="INDIA"/> <entry key="2" value="USA"/> </map> </property> <property name="customProperies"> <props> <prop key="admin">admin@example.com</prop> <prop key="support">support@example.com</prop> </props> </property> </bean> </beans>

注意这里的规律:list 和 set 用 元素填值,map 用 填键值对,props 用 填字符串键值对。面试问到 Properties 注入时,除了用 标签,还可以补充另一种方式:通过 util 命名空间从 properties 文件创建一个 properties bean,然后通过 setter 方法注入 bean 引用。

这类题通常这么答比较加分:先说出四个标签分别对应哪四种集合类型,再强调 props 只能存字符串键值对,map 键值可以是任意类型。很多面试者会把 map 和 props 混为一谈,能主动区分这一点,就能从同类面试者里脱颖而出。

4.5 自动装配的原理与歧义处理

自动装配允许 Spring 容器自动搞定 bean 之间的依赖关系,通过在 XML 配置文件中设定即可实现。自动装配可以按照如下方式设置:使用 autowire 属性的 byName、byType 等模式,或者使用 @Autowired 注解完成指定 bean 的自动装配。下面的 XML 片段展示了按名称自动装配:

<bean id="employeeDAO" class="com.example.EmployeeDAOImpl" autowire="byName" />

byName 模式根据属性名去容器中查找同名的 bean 完成装配,byType 模式根据属性类型去容器中查找匹配的 bean。使用 @Autowired 注解前,必须先配置 <context:annotation-config /> 开启注解装配。面试到这里通常会有追问:「如果 byType 找到多个候选对象怎么办?」标准答案是配合 @Qualifier 指定具体的 bean 名称消除歧义。自动装配的基本原则是:容器负责匹配,开发者负责提供清晰的 bean 定义。

5. 注解三件套与常见错误:@Required、@Autowired、@Qualifier 怎么答才不丢分

5.1 @Required、@Autowired、@Qualifier 的考点定位

@Required 注解应用于设值方法,用来检查指定属性是否被赋值;如果配置时没有给这个属性注入值,容器初始化时会抛出异常。@Autowired 更灵活,可以应用于设值方法、非设值方法、构造方法和变量,按类型自动装配所需的依赖。@Qualifier 与 @Autowired 搭配使用,用于消除特定 bean 自动装配的歧义。

不少面试者分不清 @Required 和 @Autowired 的职责差异,其实一句话可以讲明白:@Required 是强制校验「必须装配」,@Autowired 是启动「自动装配」,@Qualifier 是解决「装配哪个」。面试官如果让你举例说明这三个注解,建议按「校验 → 装配 → 指定」的逻辑展开,并说明 @Autowired 默认先按类型找,找不到唯一匹配再回退到按名称找。

5.2 构造器注入与 Setter 注入的对比:从代码面试到源码追问

构造器注入和 Setter 方法注入是依赖注入的两种最常用实现方式。构造器注入在 Bean 创建时强制传入依赖,好处是依赖不可变且必填,创建后对象状态完整;坏处是当依赖过多时构造器参数列表会变得冗长。Setter 注入在 Bean 创建后再调用 setter 方法补充依赖,好处是依赖可以选填、后续可以重新赋值;坏处是对象创建后可能处于未完全初始化的状态。

答题时建议补充目前 Spring 团队的推荐倾向:核心强制依赖优先用构造器注入,可选依赖用 Setter 注入。追问到「为什么推荐构造器注入」时,可以从不可变性和测试便利性两个角度展开。构造器注入还能有效避免循环依赖的发生,因为对象在创建阶段就明确了依赖图。

5.3 高频失分点:面试者最常踩的四个坑

第一个失分点是把 bean 作用域名称记混。global-session 是 Portlet 应用下所有 portlet 共享的全局存储变量作用域,与 Servlet 中的 session 作用域效果相同;很多面试者听到 global-session 就默认它是 Web 通用配置,这是错的。错在哪:实际项目很少用 Portlet 容器,这个作用域容易记忆错位。怎么答对:先答五个标准作用域全称,再单独说明 global-session 的使用前提是 Portlet 容器。

第二个失分点是对「单例 bean 是否线程安全」回答绝对化。有人说「Spring 单例都是安全的」,有人说「Spring 单例都不安全」,两种极端都会被面试官抓漏洞。怎么答对:框架不负责线程安全,无状态 bean 天然安全,有状态 bean 需要自行设置作用域为 prototype 或做并发控制。

第三个失分点是混淆 @Configuration 与 @ComponentScan 的职责。@Configuration 标记类是 bean 定义资源,@ComponentScan 负责扫描指定包下的组件类。常见错误是只写了 @Configuration 没加扫描路径,导致容器找不到 bean。答题模板:配置类负责定义,扫描器负责发现,容器负责装配。

第四个失分点是混淆 FileSystemResource 和 ClassPathResource 的适用场景。FileSystemResource 从文件系统路径读取,ClassPathResource 从类路径读取,后者更适合打包部署。答题时补一句「实际项目优先使用 ClassPathResource,避免依赖服务器文件系统路径」,面试观感会完全不同。

6. 面试答题节奏:从概念到源码的六步拆题法

6.1 六步拆题法:任何 Spring 问题都能套用的答题结构

第一步先复述题干概念,用一两句话精准定义,不要展开细节。第二步说明概念背后的设计动机,为什么需要它、解决什么问题,比如 IoC 是解决对象耦合问题。第三步给出核心组件或关键接口,按重要程度排列。第四步落到配置写法,用 XML 片段、注解或 Java 配置类示意,最好附上关键参数。第五步讲执行流程,从容器启动到 bean 被获取的完整链路。第六步总结优缺点或候选方案,比如构造器注入和 Setter 注入的取舍。掌握这套节奏后,任何 Spring 问题都能在 90 秒内答出层次感。

6.2 追问链路的预判:从这里准备答案不会冷场

答完「Spring Bean 生命周期」之后,面试官大概率追问:初始化顺序怎么排?答完「@Autowired 自动装配」之后,大概率追问:找不到唯一候选怎么办?答完「单例 bean 线程安全」之后,大概率追问:那你的项目里哪些 bean 是有状态的?你不需要把所有深入的答案提前背全,但要在准备每个高频考点时预设两轮追问,再准备一层答案。这份经典 25 题清单覆盖了概念背记的层面,你还需要针对每一个答案补充一段自己的项目使用场景,这也是面试官检验你放心虚不虚的关键手段。

从那以后我每次准备 Spring 面试,都强制自己把每个考点按「定义 → 动机 → 组件 → 代码 → 流程 → 取舍」六步过一遍,而且至少预演两轮追问,遇到「你怎么在项目中用到的」这类开放题就不再慌乱。现在拿这份清单,先从 IoC 与 DI、生命周期、作用域、配置方式这四块开始,每块背熟后再用六步法口头复述两遍,最后再过一遍易错点。按这个节奏准备,Spring 面试的基础分基本不会失。希望帮到你。

本文还有配套的精品资源,点击获取