spring大厂面试题梳理整理

1. Spring 是什么?核心优势有哪些?

标准答案 :Spring 是轻量级的 Java 企业级开发一站式框架,核心是IOC(控制反转)AOP(面向切面编程),旨在简化企业级开发,解耦组件依赖,提升代码可维护性和扩展性。核心优势:① 解耦核心(IOC),消除硬编码依赖;② 切面编程(AOP),统一处理日志、事务、权限等横切逻辑;③ 声明式事务,无需手动管理事务提交 / 回滚;④ 轻量级,无侵入式设计,核心包体积小,启动快;⑤ 一站式支持,整合 ORM(MyBatis)、MVC(SpringMVC)、消息队列、缓存等技术;⑥ 良好的扩展性,提供丰富的扩展接口满足定制化需求。

考点解析:考察对 Spring 核心定位的理解,避免只说功能不说核心思想,大厂关注 "解耦" 和 "简化开发" 两个核心价值。

2. Spring 为什么说是轻量级框架?和 EJB 的区别是什么?

标准答案 :Spring 的轻量级体现在:① 核心依赖少,无重量级容器依赖;② 无侵入式,无需继承 / 实现 Spring 专属类,代码可脱离 Spring 独立运行;③ 配置灵活,支持注解 / XML/JavaConfig,可按需加载模块;④ 启动和运行开销小,资源占用低。与 EJB 的核心区别:① 开发复杂度:EJB 开发繁琐,需遵循严格规范,Spring 简化开发,无繁琐配置;② 依赖耦合:EJB 组件耦合度高,依赖 EJB 容器,Spring 基于 IOC 实现低耦合;③ 轻量性:EJB 是重量级框架,容器启动慢、资源占用高,Spring 轻量高效;④ 适用场景:EJB 适用于大型分布式重量级项目,Spring 适配所有 Java 项目(小到单体,大到分布式),灵活性更高。考点解析:考察对框架设计理念的理解,大厂关注候选人对 "轻量级" 的本质认知,而非表面描述。

1. 什么是 IOC(控制反转)和 DI(依赖注入)?二者的关系是什么?

标准答案 :① IOC(控制反转):将对象的创建权、依赖管理 从业务代码转移到 Spring 容器,反转了传统 "开发者手动 new 对象" 的控制逻辑,核心是解耦;② DI(依赖注入):是 IOC 的具体实现方式 ,Spring 容器在创建 Bean 时,自动将其依赖的其他 Bean 注入到当前 Bean 中(如属性、构造方法),无需开发者手动设置依赖。二者关系:DI 是手段,IOC 是目的 ,Spring 通过 DI 的方式实现了 IOC 的核心思想。考点解析:大厂核心必问,避免将二者等同,需明确 "实现方式" 和 "核心目的" 的关系。

3. Spring 中依赖注入的方式有哪些?各有什么优缺点?

标准答案 :主流有 3 种注入方式,大厂推荐构造方法注入

  1. 构造方法注入
    • 方式:通过 Bean 的有参构造方法注入依赖,配合@Autowired/@Resource或 XML<constructor-arg>
    • 优点:依赖在 Bean 创建时就初始化,保证 Bean不可变、完全初始化,避免空指针;支持 final 修饰的依赖属性;符合 "依赖不可变" 的设计原则;
    • 缺点:依赖过多时,构造方法参数会偏多(可通过拆分 Bean 解决)。
  2. Set 方法注入
    • 方式:通过属性的 setter 方法注入依赖,配合注解或 XML<property>
    • 优点:配置灵活,可实现可选依赖(无需强制注入);适合依赖较多的场景;
    • 缺点:Bean 创建和依赖注入分离,可能出现 Bean 已创建但依赖未注入的情况;无法注入 final 属性。
  3. 字段注入(属性注入)
    • 方式:直接在成员变量上添加@Autowired/@Resource,无需构造方法和 set 方法;
    • 优点:代码简洁,开发效率高;
    • 缺点:① 依赖隐藏,无法通过构造方法明确 Bean 的依赖关系;② 只能通过 Spring 容器创建对象,手动 new 时依赖为 null,可测试性差 ;③ 违反 "面向接口编程" 和 "依赖倒置" 原则;大厂明确不推荐使用考点解析:高频追问,重点考察 "构造方法注入的优势" 和 "字段注入的弊端",需结合设计原则和工程化开发(可测试性、可维护性)分析。

4. BeanFactory 和 ApplicationContext 的区别?ApplicationContext 有哪些常用实现类?

标准答案 :二者都是 Spring IOC 容器的核心接口,ApplicationContext 是 BeanFactory 的子接口,对其进行了增强扩展:

核心区别
维度 BeanFactory ApplicationContext
初始化方式 懒加载(获取 Bean 时才创建) 饿加载(容器启动时创建所有单例 Bean)
功能 仅提供 IOC/DI 核心能力 继承 BeanFactory,增加 AOP、事务、国际化、资源加载、事件发布等功能
性能 启动快,资源占用低 启动稍慢,预加载所有单例 Bean,运行时性能更高
适用场景 轻量级场景(如嵌入式设备) 企业级开发(主流场景)
ApplicationContext 常用实现类

ClassPathXmlApplicationContext :加载类路径下的 XML 配置文件;② FileSystemXmlApplicationContext :加载磁盘路径下的 XML 配置文件;③ AnnotationConfigApplicationContext :加载注解驱动的配置类(@Configuration),主流使用;④ WebApplicationContext:Web 环境专用,整合 Servlet 容器,如 XmlWebApplicationContext、AnnotationConfigWebApplicationContext。

5. 为什么 Spring 默认 Bean 是单例?单例 Bean 的线程安全问题如何解决?

标准答案:#### 为什么默认单例?① 减少对象创建和销毁的开销,提升性能(无需频繁 new 对象,降低内存占用);② 简化依赖管理,容器中仅一个实例,避免多实例的依赖混乱;③ 大多数业务 Bean(如 Service、Dao、工具类)无状态,无需多实例。

单例 Bean 的线程安全问题及解决

单例 Bean 本身不是线程安全的 (多线程共享同一个实例,若存在可变成员变量,会出现线程安全问题);但 Spring未内置解决 ,因为 Spring 无法判断 Bean 是否有状态,核心解决原则:让 Bean 无状态化。具体解决方案:

  1. 核心方案 :不在单例 Bean(Controller/Service/Dao)中定义可变成员变量(如用户信息、请求参数、计数器),保持 Bean 无状态;
  2. 若必须有状态 :① 使用ThreadLocal 存储可变状态(每个线程独立持有一份数据,线程隔离);② 将 Bean 作用域改为prototype/request(按需创建实例);③ 使用同步锁(synchronized),但会降低性能,不推荐。考点解析:大厂高频追问,需明确 "单例的优势" 和 "线程安全的核心解决原则",避免陷入 "Spring 如何保证单例线程安全" 的误区。

6. 什么是 AOP(面向切面编程)?核心思想是什么?Spring AOP 解决什么问题?

标准答案 :① AOP(面向切面编程):是一种编程思想 ,与 OOP(面向对象编程)互补,OOP 关注纵向的业务逻辑封装,AOP 关注横向的横切逻辑 提取(如日志、事务、权限、异常处理);② 核心思想:将横切逻辑从业务代码中抽离出来 ,单独封装为 "切面(Aspect)",通过动态代理的方式,在不修改业务代码的前提下,将切面逻辑动态织入到业务方法的执行流程中(如方法执行前 / 后 / 异常时);③ Spring AOP 解决的问题:避免横切逻辑在业务代码中重复编写(代码冗余),统一管理横切逻辑,提升代码可维护性和扩展性。考点解析:考察 AOP 的核心思想,需结合 OOP 对比,明确 "横切逻辑" 的定义和 AOP 的核心价值。

7. Spring AOP 中的核心术语有哪些?分别是什么含义?

标准答案:必须掌握 6 个核心术语,是理解 AOP 的基础:

  1. 切面(Aspect) :封装横切逻辑的类(如日志切面、事务切面),结合@Aspect注解定义;
  2. 连接点(JoinPoint) :程序执行过程中的所有可织入切面的点 (如方法执行、属性修改),Spring AOP 中仅支持方法级别的连接点
  3. 切入点(Pointcut) :从所有连接点中筛选出需要织入切面的具体点,通过表达式(如 execution、@annotation)定义,是连接点的子集;
  4. 通知(Advice) :切面的具体执行逻辑 ,定义了切面在切入点的执行时机,如方法执行前、执行后;
  5. 目标对象(Target):被切面织入的原始业务对象(即被代理的对象);
  6. 代理对象(Proxy):Spring AOP 通过动态代理创建的对象,整合了目标对象的业务逻辑和切面的横切逻辑,业务代码实际调用的是代理对象;
  7. 织入(Weaving) :将切面逻辑动态融入到目标对象方法执行流程中的过程,Spring AOP 的织入发生在运行时考点解析:大厂必问,需明确各术语的关系(如切入点是连接点的子集、通知是切面的逻辑),重点记住 "Spring AOP 仅支持方法级连接点"。

8. Spring AOP 中的通知类型有哪些?各执行在什么时机?

标准答案 :核心有 5 种通知类型,需明确执行顺序(环绕通知优先级最高):

  1. 前置通知(@Before) :在目标方法执行前执行,无法阻止目标方法执行(除非抛出异常);
  2. 后置返回通知(@AfterReturning) :在目标方法正常执行完成后执行,可获取目标方法的返回值;
  3. 后置异常通知(@AfterThrowing) :在目标方法抛出异常后执行,可获取异常信息;
  4. 最终通知(@After) :在目标方法执行结束后执行(无论正常完成还是抛出异常),类似 try-catch 中的 finally,用于资源释放;
  5. 环绕通知(@Around)最强大的通知类型 ,包裹目标方法的整个执行流程 ,可在方法执行前、后、异常时执行逻辑,还能控制目标方法是否执行 、修改方法参数和返回值;需手动调用proceed()方法执行目标方法。执行顺序 :@Around(前)→ @Before → 目标方法执行 → @Around(后)→ @AfterReturning/@AfterThrowing → @After。考点解析:高频基础题,大厂常结合代码案例考察通知顺序和环绕通知的使用(如手动调用 proceed ())。

9. Spring AOP 的实现原理是什么?JDK 动态代理和 CGLIB 动态代理的区别?

标准答案 :#### Spring AOP 核心实现原理Spring AOP 基于动态代理 实现,在运行时为目标对象创建代理对象,将切面逻辑织入到代理对象中;默认优先使用 JDK 动态代理,若目标对象无实现接口,则使用 CGLIB 动态代理(Spring 5.x 后默认整合 CGLIB,无需额外引入依赖)。

JDK 动态代理 vs CGLIB 动态代理 核心区别
维度 JDK 动态代理 CGLIB 动态代理
实现基础 基于接口实现,目标对象必须实现至少一个接口 基于继承实现,通过继承目标类创建子类作为代理对象
代理对象 代理类实现目标对象的接口,是接口的实现类 代理类是目标类的子类
核心类 java.lang.reflect.ProxyInvocationHandler org.springframework.cglib.proxy.EnhancerMethodInterceptor
限制 目标对象必须实现接口,无法代理无接口的类 无法代理final类(不能继承);无法代理final方法(不能重写)
性能 Spring 5.x 后优化,性能与 CGLIB 持平 早期性能优于 JDK,现在与 JDK 持平
注意 :可通过@EnableAspectJAutoProxy(proxyTargetClass = true)强制使用 CGLIB 动态代理。
考点解析:大厂中高级必问,考察底层实现,需明确两种代理的实现基础和限制,以及 Spring 的默认选择策略。

10. Spring 中 Bean 的完整生命周期是什么?(核心步骤)

标准答案 :Spring Bean 的生命周期是从创建销毁 的全流程,核心步骤分 8 步(结合注解和接口,大厂要求按执行顺序描述):核心执行顺序

  1. 实例化(Instantiation):Spring 容器通过反射创建 Bean 的原始实例(调用无参构造方法);
  2. 属性注入(Populate):Spring 容器为 Bean 注入依赖的属性和其他 Bean(DI 核心步骤);
  3. 执行 BeanNameAware 的 setBeanName ():将 Bean 的 id/name 注入到当前 Bean 中;
  4. 执行 BeanFactoryAware 的 setBeanFactory ():将当前 BeanFactory 容器注入到 Bean 中;
  5. 执行 ApplicationContextAware 的 setApplicationContext ():若容器是 ApplicationContext,将其注入到 Bean 中(整合容器上下文);
  6. 执行 BeanPostProcessor 的前置处理(postProcessBeforeInitialization ())全局前置处理,所有 Bean 初始化前都会执行该方法,可定制化 Bean(如修改属性、增强 Bean);
  7. 执行初始化方法 :① 执行@PostConstruct注解的方法(注解方式);② 执行 InitializingBean 的 afterPropertiesSet ()(接口方式);③ 执行 XML/@Bean(initMethod = "")配置的自定义初始化方法;执行顺序:@PostConstruct → afterPropertiesSet () → 自定义 init 方法
  8. 执行 BeanPostProcessor 的后置处理(postProcessAfterInitialization ())全局后置处理 ,所有 Bean 初始化后都会执行该方法,核心用于AOP 动态代理创建(Spring AOP 在此步骤为 Bean 创建代理对象);
  9. Bean 就绪:Bean 完成初始化,进入容器的 Bean 池,可被业务代码获取和使用;
  10. 容器销毁时 :① 执行@PreDestroy注解的方法(注解方式);② 执行 DisposableBean 的 destroy ()(接口方式);③ 执行 XML/@Bean(destroyMethod = "")配置的自定义销毁方法;执行顺序:@PreDestroy → destroy () → 自定义 destroy 方法

核心记忆口诀 :实例化→属性注入→Aware 接口→BeanPostProcessor 前置→初始化方法→BeanPostProcessor 后置→就绪→销毁方法。考点解析 :大厂顶级高频考点,需按严格执行顺序 描述,重点记住BeanPostProcessor的执行时机和初始化 / 销毁方法的顺序,以及 AOP 代理创建在后置处理步骤。

11. Spring 事务的核心特性是什么?(ACID + 传播行为 + 隔离级别)

标准答案 :Spring 事务基于数据库事务,核心包含数据库事务的 ACID 特性Spring 自定义的传播行为隔离级别,是事务管理的基础:

1. 数据库事务的 ACID 特性(基础)
  • 原子性(Atomicity):事务是不可分割的最小单位,要么全部执行成功,要么全部回滚;
  • 一致性(Consistency):事务执行前后,数据库的业务规则保持一致(如转账前后总金额不变);
  • 隔离性(Isolation):多个并发事务之间相互隔离,互不干扰;
  • 持久性(Durability):事务执行成功后,修改的数据会永久保存到数据库,不会因系统故障丢失。
11. Spring 事务的传播行为(核心,大厂必问)

传播行为定义了多个事务方法相互调用时,事务的传递规则 ,Spring 定义了 7 种传播行为,常用的有 3 种,需掌握英文名称和含义:

传播行为名称 核心含义
REQUIRED(默认) 若当前有事务,则加入该事务;若当前无事务,则创建新事务(最常用,如 Service 方法调用)
REQUIRES_NEW 无论当前是否有事务,都创建新的独立事务,原有事务暂停,新事务执行完成后恢复原有事务
NESTED 嵌套事务,若当前有事务,则在当前事务中创建嵌套事务;若当前无事务,则创建新事务(嵌套事务回滚不影响外层事务,外层回滚会影响嵌套事务)
SUPPORTS 支持当前事务,若当前无事务,则以非事务方式执行
NOT_SUPPORTED 以非事务方式执行,若当前有事务,则暂停原有事务
MANDATORY 必须在事务中执行,若当前无事务,则抛出异常
NEVER 必须以非事务方式执行,若当前有事务,则抛出异常
3. Spring 事务的隔离级别(基于数据库隔离级别)

隔离级别解决并发事务的脏读、不可重复读、幻读 问题,Spring 支持 5 种隔离级别,默认使用数据库的默认隔离级别(MySQL 默认 REPEATABLE_READ,Oracle 默认 READ_COMMITTED):

  • DEFAULT:默认值,使用数据库的默认隔离级别;
  • READ_UNCOMMITTED:读未提交,允许读取未提交的事务数据,会出现脏读、不可重复读、幻读;
  • READ_COMMITTED:读已提交,只能读取已提交的事务数据,解决脏读,会出现不可重复读、幻读;
  • REPEATABLE_READ:可重复读,保证同一事务中多次读取同一数据结果一致,解决脏读、不可重复读,会出现幻读(MySQL 默认);
  • SERIALIZABLE:串行化,最高隔离级别,事务串行执行,解决所有并发问题,但性能极低,仅适用于并发量极低的场景。

12. Spring 中声明式事务和编程式事务的区别?各适用于什么场景?

标准答案 :Spring 提供两种事务管理方式,大厂推荐声明式事务(低侵入、易维护),编程式事务适用于复杂定制化场景:

1. 声明式事务
  • 实现方式 :通过 ** 注解(@Transactional)** 或 XML 配置(<tx:advice/>)实现,无需修改业务代码,属于 AOP 的典型应用;
  • 核心优点:① 低侵入,业务代码和事务管理解耦;② 配置简单,一行注解即可实现事务;③ 易维护,无需手动管理事务提交 / 回滚;
  • 核心缺点:① 灵活性稍差,无法实现复杂的事务逻辑(如动态判断是否提交);② 只能作用于方法级别,无法作用于代码块;③ 若使用代理模式,内部方法调用会导致事务失效;
  • 适用场景:90% 以上的企业开发场景(如增删改查、常规业务方法),是主流选择。
2. 编程式事务
  • 实现方式 :通过 Spring 提供的 API 手动管理事务,核心类:TransactionTemplate(推荐)、PlatformTransactionManager
  • 核心优点 :① 灵活性高,可在代码块级别实现事务,支持动态判断是否提交 / 回滚;② 无代理模式问题,内部方法调用也能生效;③ 可实现复杂的事务逻辑(如多数据源事务、嵌套事务);
  • 核心缺点:① 侵入性强,事务代码和业务代码耦合;② 代码冗余,需手动编写提交 / 回滚逻辑;
  • 适用场景:复杂的定制化事务场景(如动态根据业务结果决定是否提交、多数据源切换事务、代码块级别的事务控制)。

考点解析 :大厂必问,需明确二者的实现方式、优缺点和适用场景,重点掌握@Transactional的使用和编程式事务的推荐实现(TransactionTemplate)。

13. @Transactional 注解的工作原理是什么?哪些情况会导致事务失效?(大厂高频追问)

标准答案:@Transactional 工作原理

@Transactional是声明式事务的核心注解,基于Spring AOP实现,核心步骤:

  1. Spring 容器启动时,扫描带有@Transactional注解的类 / 方法,为其创建事务代理对象
  2. 当调用被@Transactional修饰的方法时,实际调用的是代理对象的方法
  3. 代理对象在目标方法执行前,通过PlatformTransactionManager创建事务、设置隔离级别和传播行为;
  4. 若目标方法正常执行完成 ,代理对象自动提交事务;若目标方法抛出未捕获的 RuntimeException/Error,代理对象自动回滚事务;
  5. 若目标方法抛出受检异常(Checked Exception,如 IOException),默认不回滚事务(可通过rollbackFor配置)。

14. Spring 核心注解分类?常用注解的作用是什么?

标准答案:Spring 核心注解按功能分为 5 大类,覆盖 Bean 注册、依赖注入、配置、事务、AOP,常用注解如下:

1. Bean 注册注解(将类交给 Spring 容器管理)
  • @Component:通用注解,标注任意类为 Spring Bean;
  • @Controller:标注 MVC 控制器层 Bean,配合 SpringMVC 使用;
  • @Service:标注业务逻辑层(Service)Bean;
  • @Repository:标注数据访问层(Dao/Mapper)Bean,支持异常翻译;
  • @Bean:标注在方法上,将方法返回值注册为 Spring Bean,适用于第三方类的 Bean 注册(如数据源、RedisTemplate);
  • @ComponentScan:指定 Spring 扫描 Bean 的包路径,替代 XML<context:component-scan/>
2. 依赖注入注解(注入容器中的 Bean)
  • @Autowired:Spring 原生注解,按 ** 类型(byType)** 注入,支持required = false(可选依赖);
  • @Qualifier:配合@Autowired使用,按 ** 名称(byName)** 注入,解决同类型多个 Bean 的冲突;
  • @Resource:JDK 原生注解(JSR-250),默认按 ** 名称(byName)** 注入,找不到则按类型(byType),支持指定nametype
  • @Value:注入基本类型、字符串值,或通过 SpEL 表达式(${}/#{})注入配置文件属性(如@Value("${server.port}")`)。
3. 配置类注解(替代 XML 配置)
  • @Configuration:标注类为 Spring 配置类,替代 XML 配置文件,类中的@Bean方法会被扫描;
  • @EnableAutoConfiguration:SpringBoot 核心注解,开启自动配置,根据依赖自动创建 Bean;
  • @SpringBootApplication:SpringBoot 主注解,整合@Configuration+@ComponentScan+@EnableAutoConfiguration
  • @PropertySource:加载自定义的配置文件(如 *.properties/*.yml),配合@Value使用。
4. 事务注解
  • @Transactional:标注类 / 方法,开启声明式事务,支持配置传播行为、隔离级别、回滚策略、超时等。
5. AOP 注解(基于 AspectJ)
  • @Aspect:标注类为切面(Aspect);
  • @Pointcut:定义切入点,提取公共的切入点表达式;
  • @Before/@AfterReturning/@AfterThrowing/@After/@Around:定义通知类型;
  • @EnableAspectJAutoProxy:开启 AspectJ 注解支持。
相关推荐
沉鱼.4435 分钟前
第十二届题目
java·前端·算法
努力的小郑1 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
赫瑞1 小时前
数据结构中的排列组合 —— Java实现
java·开发语言·数据结构
Victor3562 小时前
MongoDB(87)如何使用GridFS?
后端
Victor3562 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁2 小时前
单线程 Redis 的高性能之道
redis·后端
GetcharZp2 小时前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
周末也要写八哥3 小时前
多进程和多线程的特点和区别
java·开发语言·jvm
惜茶3 小时前
vue+SpringBoot(前后端交互)
java·vue.js·spring boot
宁瑶琴3 小时前
COBOL语言的云计算
开发语言·后端·golang