Spring框架面试题
深入整理Spring框架的面试题,涵盖IoC、AOP、事务、MVC等核心知识点,包含详细的答案和解析。
📋 题目分类
🎯 一、IoC容器
1. Spring IoC容器是什么?有什么好处?
答案:
IoC(Inversion of Control,控制反转) 是一种设计思想,将对象的创建和依赖关系的管理交给容器处理。
好处:
- 降低耦合度:对象之间的依赖关系由容器管理
- 提高可测试性:便于进行单元测试
- 便于维护:集中管理对象,易于维护和修改
- 代码复用:通过依赖注入实现代码复用
2. BeanFactory和ApplicationContext的区别?
答案:
区别对比:
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 功能 | 基础IoC容器 | 高级IoC容器 |
| 懒加载 | 支持懒加载 | 默认立即加载 |
| 国际化 | 不支持 | 支持MessageSource |
| 事件发布 | 不支持 | 支持ApplicationEventPublisher |
| 自动注册 | 不支持 | 支持BeanPostProcessor等自动注册 |
详细解析:
// BeanFactory使用
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = (User) factory.getBean("user");
// ApplicationContext使用
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = context.getBean("user", User.class);3. Spring Bean的作用域有哪些?
答案:
Spring Bean的作用域:
singleton(默认)
- 单例模式,整个容器中只有一个Bean实例
- 适用于无状态的Bean
prototype
- 原型模式,每次获取都创建新实例
- 适用于有状态的Bean
request
- 每个HTTP请求创建一个实例
- 仅适用于Web应用
session
- 每个HTTP Session创建一个实例
- 仅适用于Web应用
application
- 每个ServletContext创建一个实例
- 仅适用于Web应用
4. Spring Bean的生命周期?
答案:
Spring Bean的生命周期:
实例化(Instantiation)
- 调用构造器创建Bean实例
属性注入(Population)
- 注入依赖的属性和Bean
Aware接口回调
- 调用BeanNameAware、BeanFactoryAware等接口方法
BeanPostProcessor前置处理
- 调用postProcessBeforeInitialization方法
初始化(Initialization)
- 调用@PostConstruct方法
- 调用InitializingBean.afterPropertiesSet方法
- 调用init-method方法
BeanPostProcessor后置处理
- 调用postProcessAfterInitialization方法
使用阶段
- Bean可以使用
销毁(Destroy)
- 调用@PreDestroy方法
- 调用DisposableBean.destroy方法
- 调用destroy-method方法
🎯 二、AOP
5. Spring AOP的原理?
答案:
Spring AOP基于代理模式实现,主要有两种代理方式:
JDK动态代理:基于接口实现
- 需要实现接口
- 使用Proxy类和InvocationHandler
CGLIB代理:基于类继承实现
- 不需要实现接口
- 使用Enhancer类和MethodInterceptor
代理选择规则:
- 如果目标类实现了接口,默认使用JDK动态代理
- 如果目标类没有实现接口,使用CGLIB代理
- 可以通过配置强制使用CGLIB代理
6. AOP的通知类型有哪些?
答案:
AOP的通知类型:
前置通知(@Before)
- 在目标方法执行前执行
后置通知(@AfterReturning)
- 在目标方法正常返回后执行
异常通知(@AfterThrowing)
- 在目标方法抛出异常后执行
最终通知(@After)
- 无论目标方法是否异常都会执行
环绕通知(@Around)
- 可以控制目标方法的执行
示例代码:
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.service.*.*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("前置通知:" + joinPoint.getSignature().getName());
}
@Around("execution(* com.example.service.*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前");
Object result = joinPoint.proceed();
System.out.println("环绕通知后");
return result;
}
}🎯 三、事务管理
7. Spring事务的传播行为有哪些?
答案:
Spring事务传播行为:
PROPAGATION_REQUIRED(默认)
- 如果当前存在事务,则加入该事务;如果不存在,则创建一个新事务
PROPAGATION_SUPPORTS
- 如果当前存在事务,则加入该事务;如果不存在,则以非事务方式运行
PROPAGATION_MANDATORY
- 如果当前存在事务,则加入该事务;如果不存在,则抛出异常
PROPAGATION_REQUIRES_NEW
- 创建一个新事务,如果当前存在事务,则挂起当前事务
PROPAGATION_NOT_SUPPORTED
- 以非事务方式运行,如果当前存在事务,则挂起当前事务
PROPAGATION_NEVER
- 以非事务方式运行,如果当前存在事务,则抛出异常
PROPAGATION_NESTED
- 如果当前存在事务,则创建一个嵌套事务;如果不存在,则创建一个新事务
8. Spring事务的隔离级别?
答案:
Spring事务隔离级别:
ISOLATION_DEFAULT
- 使用数据库默认隔离级别
ISOLATION_READ_UNCOMMITTED
- 读未提交,最低隔离级别
ISOLATION_READ_COMMITTED
- 读已提交,解决脏读问题
ISOLATION_REPEATABLE_READ
- 可重复读,解决不可重复读问题
ISOLATION_SERIALIZABLE
- 串行化,最高隔离级别
🎯 四、循环依赖
9. Spring如何解决循环依赖?
答案:
Spring通过三级缓存解决循环依赖:
一级缓存(singletonObjects)
- 存储完全初始化好的单例Bean
二级缓存(earlySingletonObjects)
- 存储早期单例Bean(已实例化但未初始化)
三级缓存(singletonFactories)
- 存储单例Bean工厂(ObjectFactory)
解决流程:
- Bean A实例化后,将A的工厂放入三级缓存
- Bean A填充属性时需要Bean B
- Bean B实例化后,将B的工厂放入三级缓存
- Bean B填充属性时需要Bean A
- 从三级缓存获取A的工厂,创建早期A(可能返回代理对象)
- 将早期A放入二级缓存,删除三级缓存的工厂
- 将早期A注入到B
- 完成B的初始化后,将B注入到A
注意:
- 只支持单例Bean的循环依赖(通过Setter或字段注入)
- 不支持构造器注入的循环依赖
- 不支持原型Bean的循环依赖
📖 学习资源
视频教程
书籍推荐
- 《Spring源码深度解析》 - 郝佳
网站资源
✅ 学习检查清单
- [ ] 已理解IoC容器原理
- [ ] 已掌握AOP原理和应用
- [ ] 已理解事务管理机制
- [ ] 已理解循环依赖解决机制
- [ ] 已练习常见Spring面试题
- [ ] 已总结答题技巧
上一章节:Java基础面试题
下一章节:SpringBoot面试题
返回目录:面试题