1. 引言
Spring 是 Java 后端开发中最核心的框架之一,也是面试中几乎必考的内容。无论是应届生还是资深工程师,Spring 相关的问题总是面试官最青睐的考察点。本文整理了 Spring 面试中最常见的高频题目,从核心原理到实战应用,帮助你在面试中从容应对。
2. 什么是 Spring?它的核心优势是什么?
Spring 是一个轻量级的开源框架,于 2003 年由 Rod Johnson 创建,旨在解决企业级应用开发的复杂性。它的核心优势包括:
- 轻量级:Spring 框架本身是模块化的,可以根据需要引入相应的模块,基础核心约 2MB。
- 控制反转(IoC):将对象的创建和依赖管理交给容器,降低代码耦合度。
- 面向切面编程(AOP):将日志、事务、安全等横切关注点与业务逻辑分离。
- 一站式框架:Spring 提供了从数据访问、事务管理到 Web 开发的完整解决方案。
- 与主流框架无缝集成:可以轻松整合 MyBatis、Hibernate、Struts2 等框架。
3. 什么是控制反转(IoC)?什么是依赖注入(DI)?
控制反转(Inversion of Control,IoC) 是一种设计思想,指将对象的创建和对象之间的依赖关系的管理权从程序代码中反转交给容器来完成。传统开发中,对象由调用者主动创建;而在 Spring 中,对象由 IoC 容器负责创建和管理。
依赖注入(Dependency Injection,DI) 是 IoC 的一种实现方式,指容器在创建对象时,将对象所依赖的其他对象通过构造器、Setter 方法或字段等方式注入给它。
常见的依赖注入方式有三种:
- 构造器注入:通过构造函数传入依赖,推荐用于强制依赖。
- Setter 注入:通过 Setter 方法传入依赖,适合可选依赖。
- 字段注入:通过 @Autowired 注解直接注入,代码简洁但不利于测试。
4. Spring 中 Bean 的生命周期是怎样的?
Spring 容器中 Bean 的生命周期大致分为以下几个阶段:
public class UserService implements InitializingBean, DisposableBean {
public UserService() {
System.out.println("1. 实例化");
}
@Override
public void afterPropertiesSet() {
System.out.println("4. 初始化");
}
@Override
public void destroy() {
System.out.println("7. 销毁");
}
}
5. Bean 的作用域有哪些?
Spring 中 Bean 的作用域主要有以下几种:
| singleton | 默认作用域,每个容器中只存在一个 Bean 实例 |
| prototype | 每次获取都创建一个新的 Bean 实例 |
| request | 每次 HTTP 请求创建一个实例,仅在 Web 环境中有效 |
| session | 每个 HTTP Session 创建一个实例,仅在 Web 环境中有效 |
| application | 每个 ServletContext 创建一个实例,仅在 Web 环境中有效 |
| websocket | 每个 WebSocket 连接创建一个实例 |
@Component
@Scope("prototype")
public class PrototypeBean {
// 每次获取都会创建新实例
}
6. 什么是 AOP?Spring AOP 的实现原理是什么?
面向切面编程(Aspect Oriented Programming,AOP) 是一种编程范式,它将日志记录、权限校验、事务管理等横切关注点从业务逻辑中抽取出来,通过动态代理的方式在运行时织入。
Spring AOP 的实现原理基于动态代理:
- JDK 动态代理:当目标类实现了接口时,Spring 默认使用 JDK 动态代理,基于 java.lang.reflect.Proxy 生成代理类。
- CGLIB 代理:当目标类没有实现接口时,Spring 使用 CGLIB 通过生成目标类的子类来实现代理。
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.service.*.*(..))")
public void beforeLog(JoinPoint joinPoint) {
System.out.println("方法执行前:" + joinPoint.getSignature().getName());
}
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void afterReturning(Object result) {
System.out.println("方法返回:" + result);
}
}
7. Spring 中的事务管理是如何实现的?
Spring 提供了声明式事务和编程式事务两种方式:
声明式事务:通过 @Transactional 注解或 XML 配置声明事务边界,底层基于 AOP 实现,推荐使用。
编程式事务:通过 TransactionTemplate 或 PlatformTransactionManager 手动控制事务的提交和回滚。
@Service
public class OrderService {
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
// 业务逻辑
orderDao.insert(order);
// 如果这里抛出异常,事务会自动回滚
}
}
事务的传播行为是面试中的高频考点,常见的有:
- REQUIRED:默认值,如果当前存在事务则加入,否则新建事务。
- REQUIRES_NEW:无论当前是否存在事务,都新建一个独立的事务。
- NESTED:嵌套事务,如果当前存在事务则创建保存点,否则新建事务。
8. Spring MVC 的执行流程是怎样的?
Spring MVC 是 Spring 框架中用于 Web 开发的模块,其核心执行流程如下:
#mermaid-svg-ItU2lJHY7WTQWLfd{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ItU2lJHY7WTQWLfd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ItU2lJHY7WTQWLfd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ItU2lJHY7WTQWLfd .error-icon{fill:#552222;}#mermaid-svg-ItU2lJHY7WTQWLfd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ItU2lJHY7WTQWLfd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ItU2lJHY7WTQWLfd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ItU2lJHY7WTQWLfd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ItU2lJHY7WTQWLfd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ItU2lJHY7WTQWLfd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ItU2lJHY7WTQWLfd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ItU2lJHY7WTQWLfd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ItU2lJHY7WTQWLfd .marker.cross{stroke:#333333;}#mermaid-svg-ItU2lJHY7WTQWLfd svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ItU2lJHY7WTQWLfd p{margin:0;}#mermaid-svg-ItU2lJHY7WTQWLfd .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ItU2lJHY7WTQWLfd .cluster-label text{fill:#333;}#mermaid-svg-ItU2lJHY7WTQWLfd .cluster-label span{color:#333;}#mermaid-svg-ItU2lJHY7WTQWLfd .cluster-label span p{background-color:transparent;}#mermaid-svg-ItU2lJHY7WTQWLfd .label text,#mermaid-svg-ItU2lJHY7WTQWLfd span{fill:#333;color:#333;}#mermaid-svg-ItU2lJHY7WTQWLfd .node rect,#mermaid-svg-ItU2lJHY7WTQWLfd .node circle,#mermaid-svg-ItU2lJHY7WTQWLfd .node ellipse,#mermaid-svg-ItU2lJHY7WTQWLfd .node polygon,#mermaid-svg-ItU2lJHY7WTQWLfd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ItU2lJHY7WTQWLfd .rough-node .label text,#mermaid-svg-ItU2lJHY7WTQWLfd .node .label text,#mermaid-svg-ItU2lJHY7WTQWLfd .image-shape .label,#mermaid-svg-ItU2lJHY7WTQWLfd .icon-shape .label{text-anchor:middle;}#mermaid-svg-ItU2lJHY7WTQWLfd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ItU2lJHY7WTQWLfd .rough-node .label,#mermaid-svg-ItU2lJHY7WTQWLfd .node .label,#mermaid-svg-ItU2lJHY7WTQWLfd .image-shape .label,#mermaid-svg-ItU2lJHY7WTQWLfd .icon-shape .label{text-align:center;}#mermaid-svg-ItU2lJHY7WTQWLfd .node.clickable{cursor:pointer;}#mermaid-svg-ItU2lJHY7WTQWLfd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ItU2lJHY7WTQWLfd .arrowheadPath{fill:#333333;}#mermaid-svg-ItU2lJHY7WTQWLfd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ItU2lJHY7WTQWLfd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ItU2lJHY7WTQWLfd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ItU2lJHY7WTQWLfd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ItU2lJHY7WTQWLfd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ItU2lJHY7WTQWLfd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ItU2lJHY7WTQWLfd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ItU2lJHY7WTQWLfd .cluster text{fill:#333;}#mermaid-svg-ItU2lJHY7WTQWLfd .cluster span{color:#333;}#mermaid-svg-ItU2lJHY7WTQWLfd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ItU2lJHY7WTQWLfd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ItU2lJHY7WTQWLfd rect.text{fill:none;stroke-width:0;}#mermaid-svg-ItU2lJHY7WTQWLfd .icon-shape,#mermaid-svg-ItU2lJHY7WTQWLfd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ItU2lJHY7WTQWLfd .icon-shape p,#mermaid-svg-ItU2lJHY7WTQWLfd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ItU2lJHY7WTQWLfd .icon-shape .label rect,#mermaid-svg-ItU2lJHY7WTQWLfd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ItU2lJHY7WTQWLfd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ItU2lJHY7WTQWLfd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ItU2lJHY7WTQWLfd :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
用户发送请求
DispatcherServlet 接收
HandlerMapping 查找 Handler
HandlerAdapter 调用 Controller
返回 ModelAndView
ViewResolver 解析视图
渲染响应返回客户端
9. Spring 中如何解决循环依赖?
循环依赖是指 Bean A 依赖 Bean B,而 Bean B 又依赖 Bean A。Spring 通过三级缓存来解决单例模式下的循环依赖:
- 一级缓存(singletonObjects):存放已经完成初始化的单例 Bean。
- 二级缓存(earlySingletonObjects):存放提前暴露的早期 Bean 引用(尚未完成属性填充)。
- 三级缓存(singletonFactories):存放 Bean 的工厂对象,用于生成早期引用。
解决流程:当 A 创建时发现依赖 B,先去三级缓存获取 B 的早期引用并放入二级缓存;B 创建时发现依赖 A,从二级缓存拿到 A 的早期引用完成注入;B 创建完成后,A 再从缓存中拿到完整的 B 完成注入。
需要注意的是,构造器注入无法解决循环依赖,因为构造器注入在实例化阶段就需要依赖对象,此时 Bean 还未创建完成。
10. Spring Boot 与 Spring 的区别是什么?
Spring Boot 是在 Spring 框架基础上发展而来的,旨在简化 Spring 应用的搭建和开发过程。主要区别如下:
| 配置方式 | 大量 XML 或注解配置 | 自动配置,约定优于配置 |
| 启动方式 | 需要手动配置 Web 容器 | 内嵌 Tomcat/Jetty,一键启动 |
| 依赖管理 | 手动管理版本 | 通过 Starter 自动管理依赖版本 |
| 监控 | 需要额外集成 | 提供 Actuator 监控端点 |
| 部署 | 需要部署到外部容器 | 可打包为可执行 JAR 独立运行 |
11. 总结
Spring 面试题覆盖范围广,从 IoC、AOP 到事务管理、Spring MVC,再到 Spring Boot,都是面试官考察的重点。建议在准备面试时:
- 深入理解 IoC 和 DI 的核心思想,而不只是背概念。
- 掌握 Bean 生命周期和三级缓存机制,这是区分初级和高级开发者的关键。
- 结合项目实战理解 AOP 和事务管理的应用场景。
- 熟悉 Spring Boot 的自动配置原理,这是当前企业开发的主流。
希望本文能帮助你在 Spring 面试中脱颖而出,祝你面试顺利!




