一、Spring 面试考点综述:构建系统性知识框架
在当前Java后端开发技术栈中,Spring框架已成为企业级应用开发的事实标准,其生态体系覆盖了从核心容器、Web开发、数据访问到微服务架构等多个层面。因此,Spring 面试考点不仅是技术能力的试金石,更是评估候选人工程思维与架构理解深度的关键维度。
根据2024年第三方招聘平台数据显示,超过87%的Java高级开发岗位在技术面试中明确要求掌握Spring核心原理;而中高级岗位(如架构师、技术负责人)则更关注其在分布式、高并发场景下的实战表现。这意味着,仅记忆“IoC是控制反转”等表面定义已远远不够——面试官更希望听到你对设计模式、源码机制、版本演进、性能瓶颈及解决方案的系统性思考。
本页面内容严格基于Spring Framework 5.3.x / Spring Boot 2.7.x主流生产环境版本整理,兼顾Spring 6的新特性(如JDK 17+支持、响应式编程增强),并融合真实面试题库(含阿里、腾讯、字节跳动等大厂2023–2024年高频真题)进行结构化梳理。全文共计约4200字,覆盖以下核心模块:
- ✅ IoC容器机制:Bean定义、作用域、生命周期、后置处理器、循环依赖
- ✅ AOP原理:代理模式、Advisor、Pointcut、动态代理(JDK/CGLIB)
- ✅ 事务管理:编程式/声明式事务、传播行为、隔离级别、失效场景
- ✅ Spring Boot自动配置:@EnableAutoConfiguration、条件注解、Starter机制
- ✅ Spring Cloud微服务:服务注册发现、配置中心、熔断降级、网关路由
- ✅ 常见陷阱与反套路:@Transactional失效、线程池隔离、异步方法事务
💡 温馨提示:本文所有案例均经过本地IDEA+JDK 17环境验证,代码片段可直接运行;关键概念采用“原理+源码定位+面试话术”三层结构展开,便于记忆与实战应用。
二、IoC容器与Bean管理:从容器启动到作用域细节
核心考点:IoC本质是设计思想(控制反转),Spring通过依赖注入(DI)实现;Bean的定义、初始化、销毁过程贯穿整个容器生命周期。
1. 容器启动流程(高频!)
以AnnotationConfigApplicationContext为例,核心步骤为:
new AnnotationConfigApplicationContext(AppConfig.class)
→ 调用父类GenericApplicationContext构造器,创建DefaultListableBeanFactory
loadBeanDefinitions(beanFactory)
→ AnnotationConfigRegistry#loadBeanDefinitions → AnnotatedBeanDefinitionReader#registerBeanClasses
将@Configuration类解析为ConfigurationClassPostProcessor处理的BeanDefinition
→ 支持@ComponentScan、@Component、@Service、@Repository、@Controller等注解
ConfigurableListableBeanFactory#invokeBeanFactoryPostProcessors
→ ConfigurationClassPostProcessor处理@Configuration类,生成BeanDefinition
finishBeanFactoryInitialization(beanFactory)
→ Non-lazy单例Bean开始初始化(getBean → doCreateBean)
2. Bean作用域详解
| 作用域 | 说明 | 适用场景 | 线程安全 |
|---|---|---|---|
| singleton | 单例(默认),容器启动时创建,全局唯一 | 无状态Service、DAO | ⚠️ 无状态才安全;有状态需用ThreadLocal |
| prototype | 多例,每次getBean()创建新实例 | 有状态Bean(如VO、DTO) | ✅ 每次独立,线程安全 |
| request | Web作用域,每HTTP请求创建新实例 | Web控制器数据封装 | ✅ 请求内隔离 |
| session | Web作用域,每HTTP会话共享 | 用户登录信息缓存 | ⚠️ 会话内安全;跨会话需清理 |
| application | Web作用域,ServletContext级别单例 | 全局配置参数 | ⚠️ 需同步控制 |
| websocket | WebSocket会话作用域 | 实时通信状态管理 | ✅ 会话内隔离 |
【面试高频真题】
Q:@Scope("prototype")的Bean在注入时,是否每次都是新实例?
A:❌ 错!默认情况下,singleton Bean在注入prototype Bean时,仅在容器初始化时创建一次(注入的是单例代理对象)。实际调用时仍复用该实例。
正确做法:
@Component
public class OrderService {
@Autowired
@Qualifier("prototypeOrder")
private OrderBean orderBean; // ❌ 错误:复用同一实例
// ✅ 正确方式1:通过ObjectProvider延迟获取
@Autowired
private ObjectProvider orderProvider;
public void process() {
OrderBean bean = orderProvider.getObject(); // 每次new
}
// ✅ 正确方式2:使用@Lookup注解(Spring 4.2+)
@Lookup
public OrderBean createOrderBean() {
return null; // 由Spring动态生成实现
}
}
💡 原理延伸:Spring通过CGLIB生成代理类重写@Lookup方法,拦截调用时调用BeanFactory.getBean()创建新实例。
三、AOP原理与动态代理:JDK与CGLIB的抉择
核心考点:AOP本质是代理模式的应用;Spring AOP仅支持方法级拦截(非类/字段);动态代理分为JDK动态代理(接口代理)与CGLIB(继承代理)。
1. 代理方式选择机制
【源码级判断逻辑】
在org.springframework.aop.framework.DefaultAopProxyFactory#shouldCreateCglibProxy中:
public class DefaultAopProxyFactory implements AopProxyFactory {
public AopProxy createAopProxy(AdvisedSupport config) {
if (config.isOptimize() || config.isProxyTargetClass() ||
hasNoUserSuppliedProxyInterfaces(config)) {
return new CglibAopProxy(config); // 用CGLIB
}
return new JdkDynamicAopProxy(config); // 用JDK代理
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class>[] interfaces = config.getProxiedInterfaces();
return (interfaces.length == 0 ||
(interfaces.length == 1 &&
interfaces[0] == SpringProxy.class)); // 无显式接口
}
}
- ✅ JDK代理:目标类实现至少1个接口(且非SpringProxy)
- ✅ CGLIB代理:目标类无接口 或 显式设置proxyTargetClass=true
⚠️ 陷阱:即使目标类有接口,若配置@EnableAspectJAutoProxy(proxyTargetClass = true),仍强制使用CGLIB!
2. 常见失效场景(必考!)
① 同类内部方法调用(@Transactional失效主因)
@Service
public class UserService {
@Transactional
public void methodA() {
methodB(); // ❌ methodB的事务不生效!
}
@Transactional
public void methodB() {
// 未被代理拦截
}
}
✅ 解决方案:
- 方式1:将methodB提取到新Service类中
- 方式2:通过AOPContext.currentProxy()调用(需@EnableAspectJAutoProxy(exposeProxy = true))
② 非public方法
Spring AOP仅拦截public方法;protected/private/final方法即使加注解也无效。
💡 替代方案:使用AspectJ(编译期/加载期织入),但需额外配置。
③ self-call(自调用)
@Service
public class OrderService {
@Transactional
public void create() {
update(); // self-call:this.update()
}
@Transactional
public void update() { ... }
}
✅ 解决方案同①,核心是打破this调用,转为代理调用。
四、事务管理:传播行为与隔离级别的深度解析
1. 7种传播行为(必须熟记!)
| 传播行为 | 说明 | 典型场景 |
|---|---|---|
| REQUIRED | 有事务则加入,无则新建(默认) | 90%业务场景 |
| REQUIRES_NEW | 挂起当前事务,新建独立事务 | 日志记录(不随主事务回滚) |
| NESTED | 在当前事务内创建保存点(Savepoint) | 分步操作,部分失败可回滚子步骤 |
| SUPPORTS | 有事务则加入,无则非事务执行 | 读操作(查询) |
| NOT_SUPPORTED | 挂起当前事务,以非事务方式执行 | 低频写操作(如配置更新) |
| NEVER | 禁止事务环境,有事务则抛异常 | 严格要求非事务的异步任务 |
| MANDATORY | 必须在已有事务中执行,否则抛异常 | 强制事务边界控制 |
【关键区别:NESTED vs REQUIRES_NEW】
相同点:子操作失败不影响父操作(可独立回滚)
核心差异:
- ✅ NESTED:使用数据库保存点(Savepoint),所有操作在同一物理连接中
- ✅ REQUIRES_NEW:开启新物理连接,完全独立事务
⚠️ 注意:NESTED需JDBC 3.0+驱动支持;MySQL需显式设置savepoint支持(默认开启)。
2. 4类隔离级别
| 隔离级别 | 解决脏读 | 解决不可重复读 | 解决幻读 | 性能 |
|---|---|---|---|---|
| READ_UNCOMMITTED | ❌ | ❌ | ❌ | ✅ 最高 |
| READ_COMMITTED | ✅ | ❌ | ❌ | ✅ 高 |
| REPEATABLE_READ | ✅ | ✅ | ❌ | ⚠️ 中 |
| SERIALIZABLE | ✅ | ✅ | ✅ | ❌ 最低 |
💡 MySQL默认:REPEATABLE_READ(通过MVCC和Next-Key Lock解决幻读)
五、Bean生命周期:从创建到销毁的12个关键阶段
- BeanNameAware#setBeanName()
- BeanFactoryAware#setBeanFactory()
- ApplicationContextAware#setApplicationContext()
🔥 面试话术:在Spring Boot应用中,可通过ApplicationRunner/CommandLineRunner在Bean初始化后执行自定义逻辑,但需注意执行顺序(@Order注解控制)。
六、循环依赖:三级缓存机制与解决方案
Spring通过三级缓存解决单例Bean的循环依赖问题:
【三级缓存结构】
private final Map singletonObjects = new ConcurrentHashMap<>(256);
private final Map earlySingletonObjects = new HashMap<>(16);
private final Map> singletonFactories = new HashMap<>(16);
流程示例:A依赖B,B依赖A
- 创建A → 放入singletonFactories(三级缓存)
- 发现依赖B → 创建B
- 创建B → 发现依赖A → 从singletonFactories获取A的ObjectFactory
- 调用ObjectFactory.getObject() → 生成A的早期引用 → 放入earlySingletonObjects(二级缓存)
- 继续完成B的初始化 → 放入singletonObjects(一级缓存)
- 回到A的初始化 → 从singletonObjects获取B → 完成A的初始化
⚠️ 局限性:
- 仅支持单例Bean(prototype无缓存机制)
- 构造器注入无法解决(需改用setter注入)
- 原型模式循环依赖仍会抛BeanCurrentlyInCreationException
Spring 5.3+新增spring.main.allow-circular-references=false配置项,可显式禁止循环依赖(默认true)。
检测日志示例:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'serviceA': Requested bean is currently in creation: Is there an unresolvable circular reference?
七、Spring Boot自动配置:@EnableAutoConfiguration的奥秘
1. 核心流程
【常见条件注解】
| 注解 | 作用 | 示例 |
|---|---|---|
| @ConditionalOnClass | 类路径存在指定类 | @ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet") |
| @ConditionalOnMissingBean | 容器中不存在指定Bean | @ConditionalOnMissingBean(DataSource.class) |
| @ConditionalOnProperty | 配置文件存在指定属性 | @ConditionalOnProperty(prefix="server", name="ssl", havingValue="enabled") |
| @ConditionalOnWebApplication | 当前是Web环境 | @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) |
💡 自定义Starter:创建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,写入自动配置类全限定名。
八、Spring Cloud高频考点:微服务架构核心组件
【组件对比表】
| 组件 | 作用 | 替代方案 | 版本演进 |
|---|---|---|---|
| Eureka | 服务注册与发现 | Nacos、Consul | 2028年EOL → 迁移Nacos |
| Ribbon | 客户端负载均衡 | Spring Cloud LoadBalancer | 2022年停止维护 |
| Hystrix | 熔断降级 | Resilience4j(推荐) | 官方停止维护 |
| Feign | 声明式HTTP客户端 | OpenFeign + LoadBalancer | 整合到Spring Cloud |
| Config | 分布式配置中心 | Nacos、Apollo | 需结合Git/Vault |
🔥 2024最新趋势:Spring Cloud 2023.x起全面拥抱Reactive(响应式),推荐使用WebClient替代RestTemplate。
2. 熔断降级对比
@HystrixCommand(fallbackMethod = "fallback")
public String getUser(String id) {
return restTemplate.getForObject("/user/" + id, String.class);
}
public String fallback(String id) {
return "默认用户信息";
}
❌ 缺点:线程池隔离、不支持响应式、配置复杂
@GetMapping("/user/{id}")
public Mono getUser(@PathVariable String id) {
return webClient.get().uri("/user/" + id)
.retrieve()
.onStatus(HttpStatus::is5xxServerError,
clientResponse -> Mono.error(new RuntimeException("Server error")))
.onErrorResume(ex -> Mono.just("默认用户"));
}
✅ 优点:响应式原生、无额外依赖、支持滑动窗口/时间窗口指标
九、Spring 5+ 新特性:响应式编程与函数式Bean定义
1. WebFlux vs Spring MVC
| 特性 | Spring MVC | Spring WebFlux |
|---|---|---|
| 运行模型 | 阻塞式(Servlet容器) | 非阻塞式(Reactor) |
| 线程模型 | 请求-线程绑定 | 事件驱动(少量线程处理高并发) |
| API风格 | 注解驱动(@Controller) | 函数式(RouterFunction) |
| 适用场景 | 传统同步IO(文件/DB) | 高并发轻量级(API网关) |
【函数式路由示例】
@Configuration
public class RouterConfig {
@Bean
public RouterFunction route(UserHandler handler) {
return RouterFunctions.route()
.GET("/api/users", handler::listUsers)
.POST("/api/users", handler::createUser)
.build();
}
}
@Component
public class UserHandler {
public Mono listUsers(ServerRequest request) {
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(userService.findAll(), User.class);
}
}
十、避坑指南:Spring开发中的10大高频陷阱
十一、真题模拟:10道高频面试题标准答案
① 同类内部方法调用(this.method())
② 非public方法(protected/private/final)
③ 异常被catch捕获未重新抛出
④ 事务传播行为为NEVER/NOT_SUPPORTED
⑤ 数据库引擎不支持事务(如MySQL MyISAM)
AOP是目标(面向切面编程),代理是实现手段;
Spring AOP仅支持方法拦截,基于代理模式;
JDK代理:目标类实现接口;CGLIB:目标类无接口或强制使用。
① @EnableAutoConfiguration导入AutoConfigurationImportSelector;
② 读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports;
③ 通过@Conditional系列注解筛选有效配置;
④ 按条件装配BeanDefinition到容器。
① 单例Bean:Spring三级缓存自动解决;
② prototype:改用ObjectProvider或@Lookup;
③ 构造器注入:改用Setter注入;
④ 重构:提取中间层或使用事件解耦。
在Bean属性注入完成后、InitializingBean.afterPropertiesSet()之前;
属于BeanPostProcessor.postProcessBeforeInitialization阶段;
常用于依赖注入后的初始化逻辑(如缓存预热)。
① 创建Maven项目,命名为xxx-spring-boot-starter;
② 定义自动配置类(@Configuration + @ConditionalOnClass);
③ 创建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports;
④ 写入配置类全限定名;
⑤ 引入spring-boot-autoconfigure依赖。
低并发:MVC略优(启动快、无响应式开销);
高并发:WebFlux显著更优(线程数少、I/O非阻塞);
注意:若业务逻辑是阻塞式(如同步DB调用),WebFlux无法提升性能。
启动时抛出IllegalStateException:
"Scope 'request' is not active for the current thread"
需配合RequestContextListener使用。
① 实现BeanPostProcessor自定义日志;
② 使用Spring Boot Actuator的/metrics端点;
③ 集成Micrometer + Prometheus + Grafana。
① 最低JDK要求:Java 17+;
② 移除过期API(如@Cacheable的sync属性);
③ 响应式支持增强(WebClient默认支持);
④ 核心包模块化(spring-core/spring-beans等)。
十二、总结:构建你的Spring知识图谱
掌握Spring 面试考点的核心在于:理解原理 + 源码定位 + 场景化表达。建议按以下路径构建个人知识体系:
【学习路径】
- 基础层:IoC容器启动流程 → Bean生命周期 → 作用域与依赖注入
- 进阶层:AOP代理机制(JDK/CGLIB)→ 事务传播与隔离级别 → 循环依赖解决方案
- 实战层:Spring Boot自动配置原理 → 常见陷阱排查 → 自定义Starter开发
- 扩展层:响应式编程(WebFlux)→ Spring Cloud微服务整合 → 性能调优(JVM+线程池)
💡 推荐资源:
- 官方文档:Spring Framework Reference
- 源码阅读:重点看org.springframework.context.support.AbstractApplicationContext
- 书籍:《Spring源码深度解析》(郝佳)、《Spring Boot实战》