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 注解支持。
相关推荐
木辰風4 小时前
PLSQL自定义自动替换(AutoReplace)
java·数据库·sql
heartbeat..4 小时前
Redis 中的锁:核心实现、类型与最佳实践
java·数据库·redis·缓存·并发
5 小时前
java关于内部类
java·开发语言
好好沉淀5 小时前
Java 项目中的 .idea 与 target 文件夹
java·开发语言·intellij-idea
gusijin5 小时前
解决idea启动报错java: OutOfMemoryError: insufficient memory
java·ide·intellij-idea
To Be Clean Coder5 小时前
【Spring源码】createBean如何寻找构造器(二)——单参数构造器的场景
java·后端·spring
吨~吨~吨~5 小时前
解决 IntelliJ IDEA 运行时“命令行过长”问题:使用 JAR
java·ide·intellij-idea
你才是臭弟弟5 小时前
SpringBoot 集成MinIo(根据上传文件.后缀自动归类)
java·spring boot·后端
短剑重铸之日5 小时前
《设计模式》第二篇:单例模式
java·单例模式·设计模式·懒汉式·恶汉式
码农水水5 小时前
得物Java面试被问:消息队列的死信队列和重试机制
java·开发语言·jvm·数据结构·机器学习·面试·职场和发展