Spring = 帮你创建对象 + 管理对象 + 给对象注入依赖 + 给对象加功能 + 管理事务 + 处理 Web 请求


一、Spring Bean 基础

1. Spring Bean 一共有几种作用域?

傻子都懂

作用域,就是:

这个对象要创建几个?什么时候销毁?

最常见的有 6 种:

作用域 傻子理解
singleton 整个 Spring 容器就一个
prototype 每次要都给你新建一个
request 一个 HTTP 请求一个
session 一个用户会话一个
application 整个 Web 应用一个
websocket 一个 WebSocket 会话一个

最重要的是:

singleton 和 prototype。

比如:

@Service
public class UserService {
}

默认就是 singleton

意思是整个 Spring 容器里面通常只有一个 UserService


面试回答

Spring Bean 主要有 singleton、prototype、request、session、application、websocket 六种作用域。默认是 singleton,也就是 Spring 容器中只创建一个实例。prototype 则是在每次获取 Bean 时创建新的实例,其余作用域主要应用于 Web 环境。


二、@Qualifier

2. @Qualifier 注解有什么作用?

傻子都懂

假设 Spring 里面有两个:

@Service
class DogService implements AnimalService {}

@Service
class CatService implements AnimalService {}

你写:

@Autowired
private AnimalService animalService;

Spring 会懵:

“你到底要 Dog 还是 Cat?”

这时候:

@Autowired
@Qualifier("dogService")
private AnimalService animalService;

相当于告诉 Spring:

我要 Dog。


面试回答

@Qualifier 用于在存在多个同类型 Bean 时,进一步指定具体要注入哪一个 Bean,主要用于解决按类型注入时的歧义问题。


三、@Bean 和 @Component

3. @Bean@Component 有什么区别?

傻子都懂

它们都是:

把一个对象交给 Spring 管理。

区别主要在于:

@Component

放在类上

@Component
public class UserService {
}

告诉 Spring:

“这个类你帮我创建对象。”


@Bean

放在方法上

@Configuration
public class Config {

    @Bean
    public UserService userService() {
        return new UserService();
    }
}

告诉 Spring:

“这个方法返回的对象,你帮我放进容器。”

所以可以记:

@ComponentSpring自己扫描这个类。 @Bean我通过代码告诉 Spring 创建哪个对象。

@Bean 特别适合:

第三方类不能修改源码,但你又想交给 Spring 管理。


面试回答

@Component 是类级别注解,Spring 通过组件扫描自动将该类注册为 Bean;@Bean 是方法级别注解,通过配置类中的方法显式声明 Bean。@Bean 更适合注册第三方类或需要自定义实例化逻辑的对象。


四、@Component、@Controller、@Repository、@Service

4. @Component@Controller@Repository@Service 的区别?

傻子都懂

本质上:

它们都是告诉 Spring:这个类交给你管理。

只不过名字不同,代表不同职责。

@Component
   ├── @Controller   → Controller层
   ├── @Service      → Service层
   └── @Repository   → DAO/数据访问层

例如:

@Controller
class UserController

负责接收 HTTP 请求。

@Service
class UserService

负责业务逻辑。

@Repository
class UserRepository

负责数据库访问。

所以最容易记:

Controller:接请求 Service:做业务 Repository:访问数据库 Component:通用组件


面试回答

这几个注解本质上都属于 Spring 的组件注册注解,最终都可以将类注册为 Bean。区别主要是语义不同,@Controller 用于控制层,@Service 用于业务层,@Repository 用于持久层,@Component 用于通用组件。


五、@Primary

5. @Primary 有什么作用?

傻子都懂

还是刚才:

DogService
CatService

两个都是 AnimalService

如果你加:

@Primary
@Service
public class DogService implements AnimalService {
}

那么 Spring 会说:

“如果你没指定,那我默认选 Dog。”

所以:

@Qualifier = 我明确点名 @Primary = 没点名时,我优先选这个


面试回答

@Primary 用于多个同类型 Bean 存在时指定一个默认优先注入的 Bean。如果同时使用 @Qualifier,通常以 @Qualifier 指定的 Bean 为准。


六、@Value

6. @Value 有什么作用?

傻子都懂

就是:

把配置文件里面的值拿到 Java 代码里。

例如:

server.port=8080

然后:

@Value("${server.port}")
private int port;

最终:

port = 8080

还可以:

@Value("${name}")
private String name;

面试回答

@Value 用于将配置文件、环境变量或者 SpEL 表达式中的值注入到 Spring Bean 的字段、方法或构造参数中,常用于读取应用配置。


七、@ModelAttribute

7. @ModelAttribute 是干什么的?

这个在 Spring MVC 里面容易混。

傻子都懂

可以理解成:

把请求里的参数,装进一个 Java 对象。

比如请求:

/user?name=Tom&age=20

Java:

@GetMapping("/user")
public String user(@ModelAttribute User user) {
    System.out.println(user.getName());
    System.out.println(user.getAge());
}

Spring 会帮你组装:

User
name = Tom
age = 20

另外它还可以放在方法上,把公共数据放进 Model。

所以核心记忆:

@ModelAttribute = 请求参数 → Java对象 / Model数据


面试回答

@ModelAttribute 主要用于 Spring MVC 中的数据绑定,可以将请求参数绑定到 JavaBean 对象,也可以在控制器方法执行前向 Model 中添加公共数据。


八、过滤器和拦截器

8. 在 Spring 中,拦截器和过滤器有什么区别?

这是非常容易被问的题。

傻子都懂

先看整个请求:

浏览器
  ↓
Filter
  ↓
DispatcherServlet
  ↓
Interceptor
  ↓
Controller
  ↓
Service

Filter

属于:

Servlet 规范

它比 Spring MVC 更早。

可以理解成:

门卫。

所有请求先过门卫。


Interceptor

属于:

Spring MVC

它更接近 Controller。

可以理解成:

Controller 门口的保安。


最关键区别

Filter Interceptor
Servlet 规范 Spring MVC
更早执行 DispatcherServlet 之后
可以处理更广泛的请求 主要针对 Handler
与 Spring MVC 解耦 和 Spring MVC 绑定更紧

面试回答

Filter 属于 Servlet 规范,位于 Servlet 容器层,可以在请求进入 DispatcherServlet 之前处理请求;Interceptor 属于 Spring MVC,主要围绕 Handler 执行,可以在 Controller 执行前后进行拦截。Filter 更底层,Interceptor 更贴近 Spring MVC 的业务处理流程。


九、什么是循环依赖?

9. 什么是循环依赖?

傻子都懂

A 需要 B:

A → B

B 又需要 A:

B → A

于是:

A → B → A → B → A...

这就叫:

循环依赖。

例如:

class A {
    @Autowired
    private B b;
}

class B {
    @Autowired
    private A a;
}

面试回答

循环依赖是指两个或多个 Bean 之间存在相互依赖关系,例如 A 依赖 B,同时 B 又依赖 A。Spring 对部分单例 Bean 的循环依赖可以通过三级缓存机制进行解决。


十、Spring 如何解决循环依赖?

10. Spring 如何解决循环依赖?

傻子都懂

核心思想特别简单:

A 还没完全造好,就先把 A 的“半成品”放起来。

例如:

创建 A
 ↓
A 发现需要 B
 ↓
创建 B
 ↓
B 发现需要 A
 ↓
Spring:A虽然没完全创建好,但我这里有A的提前引用
 ↓
把这个A给B
 ↓
B创建完成
 ↓
A继续完成

这就是 Spring 解决部分循环依赖的大致思路。

但注意:

主要解决的是单例 Bean 的属性注入 / setter 注入循环依赖。

构造器循环依赖通常无法靠三级缓存解决。

例如:

A(A需要B)
B(B需要A)

因为 A 构造的时候就必须拿到 B,而 B 构造的时候又必须拿 A,两边都没机会先把“半成品”暴露出来。


面试回答

Spring 主要通过三级缓存解决单例 Bean 的循环依赖。Bean 在实例化后、属性填充之前,可以提前暴露引用,使另一个 Bean 能够获取该 Bean 的提前引用,从而打破循环。需要注意的是,构造器注入产生的循环依赖通常无法通过三级缓存解决。


十一、为什么要三级缓存?二级不够吗?

这个问题很容易把人问懵。

先记三个缓存

一级缓存:singletonObjects
    ↓
完整 Bean

二级缓存:earlySingletonObjects
    ↓
提前暴露的 Bean

三级缓存:singletonFactories
    ↓
能够产生 Bean 提前引用的工厂

为什么不是两个?

关键在:

AOP 代理。

假设 A 最后不是原对象:

A原对象
 ↓
代理对象

如果 B 提前拿到 A,那么 Spring 希望 B 拿到的是:

代理后的A

而不是:

原始A

三级缓存里面保存的是:

ObjectFactory

它可以在需要的时候决定:

到底应该返回原对象,还是返回代理对象。

所以三级缓存的核心价值可以粗暴记成:

为了能够“提前暴露 + 必要时生成代理”。


面试回答

二级缓存能够保存提前暴露的 Bean,但无法很好地解决循环依赖场景下的代理对象创建问题。三级缓存中的 ObjectFactory 可以延迟获取早期 Bean 引用,并允许 Spring 在这里进行 AOP 提前代理,因此三级缓存主要是为了支持循环依赖与代理机制的结合。


十二、Spring 重要模块

12. 看过源码吗?说下 Spring 重要模块

面试官如果问这个,不一定真要你讲源码几万行。

你可以按照功能回答:

Spring Core
    ↓
Spring Beans
    ↓
Spring Context
    ↓
Spring AOP
    ↓
Spring TX
    ↓
Spring JDBC / ORM
    ↓
Spring Web / WebMVC

傻子理解

模块 干什么
spring-core 核心基础
spring-beans Bean管理
spring-context IOC容器、ApplicationContext
spring-expression SpEL
spring-aop AOP
spring-tx 事务
spring-jdbc JDBC
spring-orm ORM支持
spring-web Web基础
spring-webmvc Spring MVC
spring-test 测试支持

面试回答

Spring Framework 可以按功能划分为核心容器、AOP、数据访问、事务、Web 等模块。核心容器主要包括 spring-corespring-beansspring-contextspring-expression;AOP 主要由 spring-aop 提供;事务由 spring-tx 提供;Web 层主要包括 spring-webspring-webmvc;数据访问还包括 JDBC 和 ORM 等模块。


十三、什么是 Spring IOC?

13. 什么是 Spring IOC?

这是 Spring 最核心的概念之一。

傻子都懂

以前你自己创建对象:

UserService service = new UserService();

也就是说:

对象由你创建。

IOC 后:

@Autowired
UserService service;

你不 new 了。

变成:

Spring 帮你创建对象。

所以 IOC:

控制反转。

以前:

你 → 创建对象

现在:

Spring → 创建对象

“控制”从你的代码手里:

反转到了 Spring。


面试回答

IOC,即控制反转,是一种设计思想。传统方式下对象由程序主动创建,而在 Spring 中,对象的创建、组装和生命周期由 Spring 容器负责管理,从而降低对象之间的耦合。


十四、IOC 有什么好处?

傻子都懂

最大的好处:

解耦。

以前:

UserService service = new UserService();

UserController 和 UserService 绑死。

现在:

@Autowired
private UserService service;

Controller 不需要关心:

UserService 到底怎么创建。

所以:

自己new
↓
对象之间关系很紧

Spring管理
↓
对象之间关系更松

面试回答

IOC 的核心价值是降低对象之间的耦合,将对象创建和依赖关系管理从业务代码中抽离出来,同时也便于替换实现、测试和统一管理 Bean 生命周期。


十五、DI 是什么?

15. Spring 中的 DI 是什么?

IOC 和 DI 一定要分清。

傻子都懂

IOC 是:

思想:对象由 Spring 管。

DI 是:

实现这种思想的一种方式:Spring 把依赖对象注入进去。

例如:

class A {
    @Autowired
    private B b;
}

Spring 把 B 放到 A 里面。

这就叫:

依赖注入。

一句话:

IOC 是“谁负责”,DI 是“怎么给”。


面试回答

DI,即 Dependency Injection,依赖注入,是 IOC 的具体实现方式之一。Spring 根据 Bean 之间的依赖关系,将所需要的依赖对象自动注入到目标 Bean 中。


十六、什么是 Spring Bean?

16. 什么是 Spring Bean?

傻子都懂

就是:

交给 Spring 管理的对象。

普通 Java 对象:

UserService service = new UserService();

如果这个对象被 Spring 容器管理:

UserService对象
      ↓
Spring IOC容器
      ↓
Spring Bean

所以:

Bean 本质还是一个 Java 对象。


面试回答

Spring Bean 本质上是由 Spring IOC 容器负责实例化、配置和生命周期管理的 Java 对象。


十七、BeanFactory

17. Spring 中的 BeanFactory 是什么?

傻子都懂

可以把它理解成:

Bean工厂。

你跟它说:

我要 UserService

它给你:

UserService Bean

它是 Spring 最核心、最基础的 Bean 容器接口之一。


面试回答

BeanFactory 是 Spring IOC 容器最基础的顶层接口之一,负责 Bean 的创建、获取以及生命周期管理等核心功能。


十八、FactoryBean

18. FactoryBean 是什么?

这个名字特别容易和 BeanFactory 搞混。

记忆方法

BeanFactory:工厂本身就是“Bean工厂”。 FactoryBean:一个特殊的 Bean,这个 Bean 专门用来“生产另一个对象”。

例如:

class MyFactoryBean implements FactoryBean<UserService>

Spring 管理:

MyFactoryBean
       ↓
生产
       ↓
UserService

所以:

BeanFactory 是容器。 FactoryBean 是容器里的一个“工厂型 Bean”。


面试回答

FactoryBean 是 Spring 提供的一种特殊 Bean 接口,实现该接口后,可以通过 getObject() 自定义真正需要暴露到容器中的对象。它常用于复杂 Bean 的创建以及第三方组件的整合。


十九、ObjectFactory

19. ObjectFactory 是什么?

傻子都懂

它可以理解成:

“别现在给我对象,等我需要的时候再给我。”

例如:

ObjectFactory<UserService>

调用:

factory.getObject();

才拿对象。

所以它的重点是:

延迟获取对象。

这也是 Spring 三级缓存里面很重要的东西。


面试回答

ObjectFactory 是一种延迟获取对象的工厂接口,通过 getObject() 在需要时获取对象。在 Spring 中可以用于延迟依赖获取,也是三级缓存处理循环依赖时的重要机制之一。


二十、ApplicationContext

20. ApplicationContext 是什么?

傻子都懂

可以理解为:

升级版 BeanFactory。

它不仅能:

创建Bean
获取Bean

还提供:

事件
国际化
资源加载
环境配置
自动注册

所以:

BeanFactory
    ↓
基础容器

ApplicationContext
    ↓
功能更完整的高级容器

面试回答

ApplicationContext 是 Spring 提供的高级 IOC 容器接口,它在 BeanFactory 基础上增加了事件发布、国际化、资源加载、环境配置等功能,是实际 Spring 应用中最常使用的容器。


二十一、Spring 一共有几种注入方式?

21. Spring 有哪些注入方式?

主要记 3 种:

① 构造器注入

public UserService(UserRepository repository) {
    this.repository = repository;
}

② Setter 注入

@Autowired
public void setRepository(UserRepository repository) {
    this.repository = repository;
}

③ 字段注入

@Autowired
private UserRepository repository;

面试里最好补一句:

实际开发更推荐构造器注入。

因为依赖关系明确,而且对象创建时依赖就是完整的,也更方便测试。


面试回答

Spring 常见的依赖注入方式包括构造器注入、Setter 方法注入和字段注入。实际开发中通常更推荐构造器注入,因为依赖明确、对象创建后状态更完整,也更利于单元测试。


二十二、什么是 AOP?

22. 什么是 AOP?

傻子都懂

假设系统里有 100 个方法:

method1
method2
method3
...
method100

它们全部都要:

记录日志
检查权限
开启事务
统计耗时

你如果每个方法都写:

log();
checkPermission();
...

会非常烦。

AOP 的思想:

把这些到处重复的代码单独拿出来,需要的时候自动插进去。

例如:

执行方法
 ↓
先记录日志
 ↓
执行原方法
 ↓
记录执行结果

所以:

AOP = 不修改核心业务代码,就给它增加额外功能。


面试回答

AOP,即面向切面编程,用于将日志、事务、权限、监控等横切关注点从核心业务逻辑中分离出来,通过动态代理等方式在目标方法执行的特定位置织入增强逻辑,从而降低代码重复和耦合。


二十三、Spring AOP 默认使用什么动态代理?

23. Spring AOP 默认用什么动态代理?两者区别?

Spring AOP 主要有:

JDK动态代理
CGLIB代理

JDK 动态代理

要求:

目标类实现接口。

例如:

interface UserService {}

class UserServiceImpl implements UserService {}

那么可以代理接口。


CGLIB

不要求接口。

它通过:

继承目标类生成子类代理。


最简单记忆

有接口 → JDK动态代理
没接口 → CGLIB

严格来说,Spring AOP 默认 proxyTargetClass=false 时优先使用 JDK 动态代理;如果没有合适的接口,会使用 CGLIB。


区别

JDK:
代理接口

CGLIB:
继承目标类

CGLIB 因为要继承,所以:

final classfinal method 等场景会受到限制。


面试回答

Spring AOP 支持 JDK 动态代理和 CGLIB 代理。默认情况下,如果目标类实现了接口,Spring 优先使用 JDK 动态代理;如果没有接口,则通常使用 CGLIB 创建子类代理。JDK 代理基于接口,CGLIB 基于继承生成代理子类。


二十四、Spring 拦截链

24. 能说说 Spring 拦截链的实现吗?

这个问题不用一上来背源码。

傻子都懂

假设一个方法要经过:

权限检查
 ↓
日志
 ↓
事务
 ↓
真正业务方法

Spring 会把这些增强逻辑组织成:

一条拦截链。

执行:

Interceptor 1
 ↓
Interceptor 2
 ↓
Interceptor 3
 ↓
目标方法

每一个拦截器内部通过:

proceed()

继续往下执行。


面试回答

Spring AOP 的拦截链主要通过 MethodInterceptor 和 MethodInvocation 等机制实现。多个 Advisor 最终会转换成拦截器链,目标方法调用时通过 proceed() 逐个执行拦截器,直到最终执行目标方法。


二十五、Spring AOP 和 AspectJ

25. Spring AOP 和 AspectJ 有什么区别?

傻子都懂

两者都干:

切面编程。

但方式不一样。

Spring AOP

主要:

运行时动态代理。

也就是:

原对象
 ↓
代理对象
 ↓
执行增强

AspectJ

更强。

它可以:

在编译期或者加载期把代码织进去。

所以 AspectJ 能处理更广泛的连接点,而 Spring AOP 主要围绕方法执行。


面试回答

Spring AOP 主要基于运行时代理实现,使用 JDK 动态代理或 CGLIB,主要针对 Spring Bean 的方法执行进行增强。AspectJ 属于更完整的 AOP 实现,可以通过编译期织入或加载期织入实现更强的切面能力,支持更多类型的连接点。


二十六、Spring Bean 生命周期

26. 说下 Spring Bean 的生命周期

这道题建议记成:

实例化 → 属性注入 → 初始化 → 使用 → 销毁

完整一点:

BeanDefinition
 ↓
实例化
 ↓
属性注入
 ↓
Aware回调
 ↓
BeanPostProcessor前置处理
 ↓
初始化
 ↓
BeanPostProcessor后置处理
 ↓
得到最终Bean
 ↓
使用
 ↓
销毁

其中初始化经常包括:

@PostConstruct
InitializingBean
init-method

销毁可能包括:

@PreDestroy
DisposableBean
destroy-method

傻子版

就是:

出生 → 穿衣服 → 做初始化 → 上班 → 下班销毁


面试回答

Spring Bean 生命周期主要包括 Bean 实例化、属性依赖注入、Aware 回调、BeanPostProcessor 前后置处理、初始化、使用以及销毁等阶段。最终返回给业务代码的 Bean 可能已经经过后置处理器增强,例如生成 AOP 代理。


二十七、如何理解 Spring MVC?

27. 说下对 Spring MVC 的理解

傻子都懂

Spring MVC 是:

专门处理 HTTP 请求的。

比如浏览器:

GET /user/1

Spring MVC 负责:

收到请求
 ↓
找到哪个Controller
 ↓
调用哪个方法
 ↓
把参数传进去
 ↓
拿结果
 ↓
返回给浏览器

面试回答

Spring MVC 是基于 MVC 设计模式的 Web 框架,核心职责是处理 HTTP 请求,将请求映射到对应的 Controller 方法,完成参数绑定、业务调用以及响应结果处理。


二十八、Spring MVC 工作原理

28. Spring MVC 具体工作原理?

这道题直接记流程:

浏览器
 ↓
DispatcherServlet
 ↓
HandlerMapping
 ↓
找到 Controller 方法
 ↓
HandlerAdapter
 ↓
执行 Controller
 ↓
返回 ModelAndView / ResponseBody
 ↓
ViewResolver(视图场景)
 ↓
返回响应

每个东西干什么?

DispatcherServlet

总指挥。

HandlerMapping

找人:

“这个 URL 应该找哪个 Controller?”

HandlerAdapter

帮总指挥真正执行 Controller。

Controller

干业务。

ViewResolver

找页面。

不过现在 Spring Boot 的 REST API 大量使用:

@RestController

直接返回 JSON,所以很多时候不会走传统 JSP 视图解析。


面试回答

Spring MVC 以 DispatcherServlet 为核心。请求首先进入 DispatcherServlet,然后通过 HandlerMapping 找到对应的 Handler,再由 HandlerAdapter 执行 Controller 方法,完成参数解析和业务调用,最后根据返回结果进行消息转换或视图解析,形成 HTTP 响应。


二十九、Spring MVC 父子容器

29. Spring MVC 父子容器是什么?

傻子都懂

可以理解成:

父容器
Spring根容器
    │
    └──── 子容器
          Spring MVC容器

一般:

父容器

放:

Service
Repository
DataSource

子容器

放:

Controller
HandlerMapping
HandlerAdapter

关键规则:

子容器可以访问父容器,父容器不能访问子容器。

就像:

父公司
 ↑
知道子公司

子公司
 ↑
可以使用总公司的资源

面试回答

在传统 Spring MVC 架构中,通常存在 Root WebApplicationContext 和 WebApplicationContext 的父子关系。父容器主要管理 Service、Repository 等业务 Bean,子容器主要管理 Controller 和 MVC 相关组件。子容器可以访问父容器中的 Bean,但父容器不能直接访问子容器中的 Bean。


三十、Spring 用到了哪些设计模式?

30. Spring 中有哪些设计模式?

这一题不要背 20 个。

重点说这几个:

工厂模式

BeanFactory

创建 Bean。

单例模式

默认 Bean:

singleton

代理模式

Spring AOP:

原对象
 ↓
代理对象

模板方法模式

例如:

JdbcTemplate

把固定流程写好,你只需要填具体逻辑。

观察者模式

Spring 事件:

ApplicationEvent
ApplicationListener

策略模式

不同策略实现不同算法。

责任链模式

Spring MVC / AOP 的拦截链都可以体现这种思想。


面试回答

Spring 中大量使用设计模式,例如 BeanFactory 体现工厂模式,默认单例 Bean 体现单例模式,AOP 采用代理模式,JdbcTemplate 体现模板方法模式,ApplicationEvent 体现观察者模式,同时在 MVC 和 AOP 等模块中也可以看到策略模式和责任链思想。


三十一、Spring 事务隔离级别

31. Spring 事务有几个隔离级别?

这个问题要稍微注意:

Spring 的 Isolation 枚举通常包括:

DEFAULT
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SERIALIZABLE

也就是:

5 个枚举值。

但真正的标准数据库隔离级别是:

4 个。

DEFAULT 的意思:

使用数据库默认隔离级别。


四种标准隔离级别

读未提交
读已提交
可重复读
串行化

等级越高:

数据隔离性 ↑
并发性能 ↓

面试回答

Spring 事务隔离级别在 Isolation 枚举中包括 DEFAULT 以及四种标准数据库隔离级别:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ 和 SERIALIZABLE。其中 DEFAULT 表示使用数据库自身的默认隔离级别。


三十二、Spring 事务传播行为

32. Spring 有哪几种事务传播行为?

一共:

7 种。

最重要的是前 3 个:

REQUIRED
REQUIRES_NEW
NESTED

另外:

SUPPORTS
NOT_SUPPORTED
MANDATORY
NEVER

最容易记

REQUIRED

有事务就加入,没有就创建。

REQUIRES_NEW

不管有没有,我重新开一个。

NESTED

在当前事务里面创建嵌套事务。


面试回答

Spring 提供 7 种事务传播行为,包括 REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER 和 NESTED。其中 REQUIRED 是最常用的,表示当前存在事务则加入,不存在则创建新事务;REQUIRES_NEW 则会挂起当前事务并创建一个新事务。


三十三、事务传播行为有什么用?

傻子都懂

假设:

下单
 ├── 创建订单
 ├── 扣库存
 └── 记录日志

这些方法都有事务。

问题是:

到底应该一起提交,还是分开提交?

传播行为就是解决:

“别人调用我的时候,我应该跟着他的事务走,还是自己开一个?”

例如:

订单事务
   ↓
日志

如果日志使用:

REQUIRES_NEW

那么订单事务失败:

日志事务也可能已经独立提交。


面试回答

事务传播行为用于定义一个事务方法被另一个事务方法调用时,两个方法之间应该如何处理事务边界,例如加入现有事务、创建新事务、挂起当前事务等,从而控制复杂业务场景中的事务组合方式。


三十四、Spring 的优点

34. Spring 有什么优点?

不要只说“简单”。

核心可以说:

IOC
AOP
事务管理
模块化
解耦
生态完善

傻子版

Spring 相当于:

把企业开发中很多麻烦的事情统一管起来。

比如:

对象创建 → Spring管
依赖关系 → Spring管
事务 → Spring管
AOP → Spring管
Web → Spring MVC

面试回答

Spring 的主要优势包括 IOC 降低对象耦合、AOP 实现横切逻辑复用、统一事务管理、模块化设计以及完善的生态体系。同时它具有较好的扩展性和可测试性,因此成为 Java 企业级开发的重要基础框架。


三十五、Spring AOP 术语

35. Spring AOP 相关术语有哪些?

这一题建议直接记:

Aspect
Join Point
Pointcut
Advice
Target
Proxy
Weaving
Advisor

傻子版

假设:

public void buy() {}

Target

被增强的原对象。

Aspect

“我这个切面负责干什么。”

比如日志切面。

Join Point

可以被增强的位置。

Pointcut

我要增强哪些位置。

Advice

到底增加什么代码。

Proxy

Spring 创建出来的代理对象。

Weaving

把增强逻辑织入目标对象执行过程。


面试回答

Spring AOP 中常见概念包括 Aspect、Join Point、Pointcut、Advice、Target、Proxy 和 Weaving。其中 Pointcut 用于匹配需要增强的连接点,Advice 表示具体增强逻辑,Target 是目标对象,Proxy 是 Spring 创建的代理对象,Weaving 则表示将切面逻辑应用到目标对象的过程。


三十六、Spring 通知有哪些类型?

36. Spring Advice 有哪些类型?

最常见的 5 种:

Before
After
AfterReturning
AfterThrowing
Around

傻子版

假设:

执行 buy()

Before

买之前干点事。

After

买完之后干点事。

AfterReturning

买成功之后干点事。

AfterThrowing

买失败、抛异常之后干点事。

Around

买之前、买之后都能控制,而且可以决定到底执不执行原方法。

所以:

Around 最强。


面试回答

Spring AOP 常见通知类型包括前置通知 Before、后置通知 After、返回通知 AfterReturning、异常通知 AfterThrowing 和环绕通知 Around。环绕通知可以通过 ProceedingJoinPoint 控制目标方法是否执行,并在执行前后增加逻辑。


三十七、IOC 容器初始化过程

37. Spring IOC 容器初始化过程?

这道题和“Spring 启动过程”有区别。

IOC 初始化可以简单理解:

读取配置
 ↓
扫描 Bean
 ↓
生成 BeanDefinition
 ↓
注册 BeanDefinition
 ↓
执行 BeanFactoryPostProcessor
 ↓
实例化 Bean
 ↓
依赖注入
 ↓
初始化
 ↓
BeanPostProcessor
 ↓
放入单例池

最重要的两个东西

BeanDefinition

可以理解成:

Bean的说明书。

比如:

这个Bean叫什么
是什么类型
作用域是什么
依赖谁

Bean实例

真正创建出来的:

UserService对象

面试回答

Spring IOC 容器初始化首先加载配置并完成组件扫描,将 Bean 信息解析为 BeanDefinition 并注册到容器中,然后通过 BeanFactoryPostProcessor 对 BeanDefinition 进行处理,在实例化 Bean 后完成依赖注入、初始化以及 BeanPostProcessor 前后置处理,最终将单例 Bean 放入单例缓存中供后续使用。


三十八、Spring Bean 注册到容器有哪些方式?

38. Spring Bean 注册有哪些方式?

常见的有:

@Component 系列

@Component
@Service
@Controller
@Repository

@Bean

@Bean
public UserService userService() {}

@Import

@Import(UserConfig.class)

④ XML

老项目常见:

<bean ... />

⑤ 编程方式注册 BeanDefinition

例如:

BeanDefinitionRegistry

这种属于比较底层的方式。


面试回答

Spring Bean 常见注册方式包括组件扫描注册 @Component 及其派生注解、配置类中的 @Bean@Import 导入、XML 配置以及通过 BeanDefinitionRegistry 等 API 进行编程式注册。


三十九、Spring 自动装配有哪些方式?

39. Spring 自动装配方式有哪些?

这里有一个面试坑:

“自动装配”有不同语境。

现在最常见的是:

@Autowired
@Resource

以及构造器注入。

Spring 传统 XML 时代还有:

byName
byType
constructor

所以面试最好这样回答。


傻子版

本质都是:

“Spring 自动帮我找到我需要的对象。”

比如:

@Autowired
private UserService userService;

Spring:

“你要 UserService?我给你找。”


面试回答

Spring 依赖注入常见方式包括 @Autowired@Resource 以及构造器注入。从传统 XML 自动装配模式来看,还存在 byName、byType、constructor 等方式。现代 Spring 开发中通常使用注解注入和构造器注入。


四十、Spring 事务什么时候会失效?

40. Spring 事务在什么情况下会失效?

这题非常重要。

最经典的几个:

① 方法不是 public

@Transactional
private void test()

通常不能按预期工作。

② 同类内部调用

例如:

class UserService {

    public void A() {
        B();
    }

    @Transactional
    public void B() {}
}

A 里面直接调用 B:

this.B()

没有经过 Spring 代理。

因此事务可能失效。

这是最常问的。


③ 异常被自己吃掉

try {
    ...
} catch (Exception e) {
}

异常没继续抛出去。

Spring:

“你都说没异常了,那我正常提交。”


④ 抛出的异常不符合回滚规则

默认情况下,Spring 声明式事务主要针对:

RuntimeException 和 Error

进行回滚。

如果是受检异常,需要根据配置决定。


⑤ Bean 没交给 Spring 管理

你自己:

new UserService();

那当然没有 Spring 代理。


⑥ 数据库本身不支持事务

例如使用不支持事务的存储引擎/操作场景。


面试回答

Spring 声明式事务依赖代理机制实现,因此常见失效场景包括 Bean 没有被 Spring 管理、事务方法没有经过代理调用、同类内部方法调用、方法可见性或代理机制不满足要求、异常被捕获后没有继续抛出,以及异常类型不符合默认回滚规则等。


四十一、Spring 启动过程

41. 说说 Spring 启动过程?

如果是普通 Spring:

创建 ApplicationContext
 ↓
读取配置
 ↓
扫描 Bean
 ↓
注册 BeanDefinition
 ↓
执行各种 BeanFactoryPostProcessor
 ↓
注册 BeanPostProcessor
 ↓
实例化非懒加载单例 Bean
 ↓
依赖注入
 ↓
Bean初始化
 ↓
容器启动完成

如果是 Spring Boot:

main()
 ↓
SpringApplication.run()
 ↓
创建 ApplicationContext
 ↓
准备环境
 ↓
加载配置
 ↓
自动配置
 ↓
扫描 / 注册 Bean
 ↓
刷新 IOC 容器
 ↓
创建 Bean
 ↓
启动内嵌 Web 容器
 ↓
应用启动完成

注意:

Spring IOC 初始化是 Spring 启动过程的一部分。


面试回答

Spring 启动的核心过程是创建并刷新 ApplicationContext,包括准备环境、加载配置、注册 BeanDefinition、执行 BeanFactoryPostProcessor、注册 BeanPostProcessor、实例化非懒加载单例 Bean、完成依赖注入和初始化,最终完成容器启动。Spring Boot 则在此基础上进一步完成自动配置、内嵌 Web 容器启动等工作。


四十二、Spring 的单例 Bean 有并发安全问题吗?

42. Spring 单例 Bean 是否有并发安全问题?

答案:

有可能。

这个题非常容易误答成:

“Spring 单例 Bean 是线程安全的。”

这是错误的。

傻子都懂

假设:

@Service
public class UserService {

    private int count = 0;
}

Spring 只创建:

一个 UserService

但可能有:

100个线程
   ↓
同时访问这个UserService

如果大家同时修改:

count

就有线程安全问题。

所以:

单例 ≠ 线程安全。


什么情况下比较安全?

如果 Bean 是:

无状态的。

例如:

@Service
public class UserService {

    public User getUser(Long id) {
        return userMapper.selectById(id);
    }
}

没有保存会变化的共享成员变量。

这种通常没问题。


面试回答

Spring 单例 Bean 本身并不保证线程安全。因为单例 Bean 会被多个线程共享访问,如果 Bean 内部存在可变共享状态,就可能产生线程安全问题。实际开发中通常将 Service 等 Bean 设计为无状态对象,尽量避免保存线程相关的可变成员变量;如果确实存在共享状态,则需要通过锁、并发容器等机制保证线程安全。


最后:把这 42 道题压缩成一张“脑图”

你面试前真正需要建立的是下面这套关系:

                    Spring
                      │
        ┌─────────────┼─────────────┐
        ↓             ↓             ↓
       IOC            AOP          MVC
        │             │             │
        │             │             └→ 处理HTTP请求
        │             │
        │             └→ 给方法增加额外功能
        │                   │
        │                   ├→ JDK代理
        │                   └→ CGLIB
        │
        ├→ BeanFactory
        ├→ ApplicationContext
        ├→ Bean
        ├→ DI
        ├→ Bean生命周期
        ├→ Bean作用域
        ├→ Bean注册
        └→ 循环依赖
               │
               └→ 三级缓存

                    Spring事务
                         │
              ┌──────────┴──────────┐
              ↓                     ↓
          隔离级别                传播行为
              │                     │
       读未提交                   REQUIRED
       读已提交                   REQUIRES_NEW
       可重复读                   NESTED
       串行化                     ...

你可以把整套 Spring 面试题归纳成 5 个核心问题

1. Spring 帮我管理什么? → Bean / IOC 2. Spring 怎么把对象联系起来? → DI / 自动装配 3. Spring 怎么给对象加功能? → AOP / 动态代理 4. Spring 怎么处理 Web 请求? → Spring MVC 5. Spring 怎么管理数据库事务? → 事务 / 隔离 / 传播

然后再把:

Bean 生命周期、循环依赖、三级缓存、BeanFactory、FactoryBean、ApplicationContext

看成是 IOC 的进阶问题

把:

Advice、Pointcut、拦截链、AspectJ

看成是 AOP 的进阶问题

把:

事务失效、传播行为、隔离级别

看成是 事务的进阶问题