3.1 单例 Bean 线程安全
Spring 的 Bean 默认是单例的。是否线程安全取决于 Bean 是否有状态(成员变量)。无状态的 Bean 是线程安全的。
3.2 AOP
是什么
AOP(面向切面编程):将散落在各个方法中的重复代码(日志、权限、事务等)抽取出来统一管理,在运行时自动”织入”到目标方法中,实现业务逻辑与横切逻辑的解耦。
核心术语
| 术语 | 含义 |
|---|---|
| 切面(Aspect) | 封装横切逻辑的类 |
| 连接点(Join Point) | 所有可被拦截的方法 |
| 切入点(Pointcut) | 实际被拦截的方法(表达式匹配) |
| 通知(Advice) | 切面中要执行的具体逻辑 |
| 织入(Weaving) | 将切面代码插入目标方法的过程 |
五种通知类型
| 通知 | 执行时机 | 特点 |
|---|---|---|
@Before | 方法执行前 | 不能阻止方法执行 |
@AfterReturning | 方法正常返回后 | 可获取返回值 |
@AfterThrowing | 方法抛异常后 | 可获取异常对象 |
@After | 方法执行完毕后(无论成功失败) | 类似 finally |
@Around | 环绕整个方法 | 最强大,可控制是否执行、修改返回值 |
底层原理
Spring AOP 基于动态代理:
- JDK 动态代理:目标类实现了接口 → 基于接口生成代理
- CGLIB 动态代理:目标类没实现接口 → 通过继承生成子类代理
一句话记忆:AOP = 把重复的”外围代码”抽出来,Spring 自动帮你”贴”到目标方法上,业务代码只关心核心逻辑。
3.3 Spring 事务失效场景
情景一:异常被捕获处理
原因:事务通知只有捕捉到异常才会回滚,如果目标自己 catch 处理掉了异常,事务无法感知。
解决:在 catch 块中抛出异常。
情景二:抛出检查异常
Spring 默认只回滚非检查异常(RuntimeException 及其子类)。
解决:配置 rollbackFor 属性。
情景三:非 public 方法
Spring AOP 基于动态代理,非 public 方法无法被代理,事务失效。
3.4 Bean 生命周期与循环依赖
Bean 生命周期
核心流程:
构造函数 → 依赖注入 → Aware 接口 → BeanPostProcessor#before
→ InitializingBean → 自定义 init → BeanPostProcessor#after(AOP 发生地)
代码示例:
@Service
public class UserService implements BeanNameAware, InitializingBean {
private String beanName;
// 【第一步】构造函数
public UserService() {
System.out.println("1. [构造函数] 实例化 Bean");
}
// 【第三步】Aware 接口回调
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("2. [Aware接口] 获知自己的名字: " + name);
}
// 【第五步】初始化方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("4. [InitializingBean] 属性设置完毕");
}
// 【第六步】自定义 init 方法
public void myInit() {
System.out.println("5. [自定义Init] 执行自定义初始化逻辑");
}
}
循环依赖
Spring 的死循环:A 依赖 B,B 依赖 A → 实例化嵌套,无法完成。
三级缓存解决:
| 缓存 | 名称 | 存放内容 |
|---|---|---|
| 一级缓存 | singletonObjects | 完全初始化好的 Bean |
| 二级缓存 | earlySingletonObjects | 早期的半成品 Bean(已实例化但未注入) |
| 三级缓存 | singletonFactories | Bean 工厂(可生成代理对象) |
构造方法导致的循环依赖:三级缓存也解决不了!因为构造方法是在实例化阶段执行的,连半成品都拿不到。
3.5 Spring MVC 执行流程
Spring MVC = 基于 Servlet 技术构建的、以 DispatcherServlet 为总指挥的、帮你自动化处理 HTTP 请求全流程的 Web 框架。
3.6 Spring Boot 自动配置
核心流程:
-
引导类上的
@SpringBootApplication封装了三个注解:@SpringBootConfiguration@EnableAutoConfiguration(核心)@ComponentScan
-
@EnableAutoConfiguration通过@Import导入配置选择器,读取 classpath 下META-INF/spring.factories中的配置类全类名 -
条件注解(如
@ConditionalOnClass)判断是否有对应的 class 文件,有则加载该配置类的所有 Bean 到容器
3.7 MyBatis
执行流程
- 映射文件加载 — 加载相关配置
- 构建会话工厂 — 全局唯一,生成
SqlSession - 创建会话 — 项目与数据库的会话,包含执行 SQL 的所有方法
- 调用 Executor 执行器 — 真正执行数据库操作,也负责查询缓存的维护
- MappedStatement 对象 — 将数据参数转变为数据库框架可理解的形式
一级缓存 vs 二级缓存
| 缓存 | 作用域 | 默认状态 |
|---|---|---|
| 一级缓存 | SqlSession 级别 | 默认开启,Session flush/close 后清空 |
| 二级缓存 | 全局(Mapper 级别) | 需手动开启 |
SqlSession = 完成一次数据库操作的临时通道。用完即开,用完即关,专人专用。