Day 011 — Spring 全家桶深度拆解

📅 2026-07-25 | 🏷️ Java · 后端方向 | ⏱️ 建议 5h | 🎯 Spring 是 Java 面试的绝对核心------IOC/AOP/Boot 三位一体


📌 今日知识地图

复制代码
Spring 面试全景
│
├── 模块一:Spring IOC
│   ├── BeanFactory vs ApplicationContext
│   ├── Bean 生命周期(12 步完整版)
│   ├── 三级缓存 & 循环依赖(面试最难!)
│   └── 依赖注入:@Autowired/@Resource/构造器注入
│
├── 模块二:Spring AOP
│   ├── JDK 动态代理 vs CGLIB
│   ├── @Transactional 原理 & 失效的 6 种场景
│   ├── 事务传播行为(7 种)
│   └── 事务隔离级别
│
├── 模块三:Spring Boot
│   ├── 自动配置原理(@SpringBootApplication 拆解)
│   ├── starter 机制 & 自定义 starter
│   ├── @Conditional 条件装配
│   └── 配置文件加载优先级
│
├── 模块四:Spring MVC
│   ├── DispatcherServlet 完整请求流程
│   ├── 拦截器 vs 过滤器 vs AOP
│   └── 统一异常处理
│
├── 模块五:MyBatis
│   ├── 核心执行流程(SqlSession → Executor → StatementHandler)
│   ├── 一级缓存 vs 二级缓存
│   ├── #{} vs ${}(SQL 注入)
│   └── 插件机制(Interceptor + 动态代理)
│
└── 面试题精选(10 道 + 公司标签)

模块一:Spring IOC

1.1 IOC 解决了什么问题?

复制代码
没有 IOC:
  class UserService {
      private UserDao dao = new UserDaoImpl();  // 自己 new 依赖
  }
  问题:UserService 和 UserDaoImpl 紧耦合,换实现要改代码

有 IOC:
  class UserService {
      @Autowired
      private UserDao dao;  // Spring 帮你注入
  }
  优势:UserService 只依赖接口,实现可以随时换(DI 实现 IOC)

IOC(控制反转):把对象的创建和管理权交给 Spring 容器,需要时注入。

DI(依赖注入):IOC 的具体实现方式。三种注入方式:

方式 示例 推荐度
构造器注入 public X(Service s) {} 推荐(不可变、非空、易测试)
Setter 注入 public void setS(Service s) {} 可选依赖用
字段注入 @Autowired private Service s; 不推荐(难以测试、隐藏依赖)

1.2 BeanFactory vs ApplicationContext

维度 BeanFactory ApplicationContext
定位 底层容器,IOC 核心 高级容器,企业级功能
Bean 加载 懒加载(首次 getBean 才初始化) 预加载(启动时初始化所有单例 Bean)
功能 基本 DI DI + AOP + 事件 + 国际化 + 资源加载 + ...
使用 几乎不直接用 一切 Spring 应用的入口
复制代码
ApplicationContext 常用实现:
  ClassPathXmlApplicationContext  ← XML 配置
  AnnotationConfigApplicationContext  ← 注解配置
  Spring Boot:自动创建 AnnotationConfigServletWebServerApplicationContext

1.3 Bean 生命周期(面试必背 12 步)

复制代码
1. 实例化(Instantiation)
   → 通过反射调用构造器创建对象实例

2. 属性赋值(Populate Properties)
   → @Autowired / @Value / @Resource 注入

3. BeanNameAware.setBeanName()
   → 让 Bean 知道自己在容器中的名称

4. BeanFactoryAware.setBeanFactory()
   → 让 Bean 获取 BeanFactory 引用

5. ApplicationContextAware.setApplicationContext()
   → 让 Bean 获取 ApplicationContext 引用

6. BeanPostProcessor.postProcessBeforeInitialization()
   → 初始化前置处理(如 @PostConstruct 注解的处理)

7. @PostConstruct 标注的方法
   → 初始化回调

8. InitializingBean.afterPropertiesSet()
   → 属性设置完毕后的回调

9. 自定义 init-method
   → @Bean(initMethod = "init")

10. BeanPostProcessor.postProcessAfterInitialization()
    → 初始化后置处理(AOP 代理对象在这里生成!)

11. Bean 就绪,可以被使用了

12. @PreDestroy / DisposableBean.destroy() / destroy-method
    → 销毁回调
java 复制代码
// 最精简的记忆方式:
// 创建 → 注入 → Aware → 前置处理 → 初始化 → 后置处理(AOP) → 就绪 → 销毁

1.4 三级缓存 & 循环依赖(面试最难知识点!)

java 复制代码
// ═══════════════════════════════════════
// 三级缓存的定义
// ═══════════════════════════════════════
// 一级缓存(singletonObjects):  完全初始化好的单例 Bean
// 二级缓存(earlySingletonObjects):早期暴露的半成品 Bean(已实例化但未属性填充)
// 三级缓存(singletonFactories):  生成半成品 Bean 的工厂(Lambda 表达式)

// ═══════════════════════════════════════
// 循环依赖场景:A 依赖 B,B 依赖 A
// ═══════════════════════════════════════

// 解决流程:
// 1. 创建 A:实例化 → 将 A 的 ObjectFactory 放入三级缓存 → 属性填充时发现需要 B
// 2. 创建 B:实例化 → 将 B 的 ObjectFactory 放入三级缓存 → 属性填充时发现需要 A
// 3. B 从三级缓存获取 A 的 ObjectFactory → 调用 getObject() 获取 A 的半成品
//    → 将 A 的半成品放入二级缓存 → 移除三级缓存中 A 的工厂
// 4. B 注入 A 的半成品 → B 完成初始化 → 将完整的 B 放入一级缓存
// 5. A 注入完整的 B → A 完成初始化 → 将 A 的半成品升级为完整的 A
//    → 将完整的 A 放入一级缓存 → 移除二级缓存中 A 的半成品

// ═══════════════════════════════════════
// 为什么需要三级缓存,而不是两级?
// ═══════════════════════════════════════
// 答案:AOP!

// 如果只有两级缓存(二级直接存半成品对象):
//   → 当 B 注入 A 时,拿到的是原始对象
//   → 但 A 可能需要被 AOP 代理
//   → 如果 A 被代理了,B 注入的应该是代理对象而非原始对象
//   → 但此时 A 还没完成属性填充,无法确定是否要生成代理

// 三级缓存的精妙之处:
//   → 三级缓存存的不是对象,而是 ObjectFactory(Lambda)
//   → getObject() 内部会检查是否需要 AOP 代理 → 需要就返回代理对象,不需要就返回原始对象
//   → 无论后续属性如何变化,这个 Lambda 都能返回"正确的版本"

// ═══════════════════════════════════════
// 循环依赖不能解决的场景
// ═══════════════════════════════════════
// ① 构造器注入的循环依赖 → 实例化就无法完成,三级缓存救不了
//    解决:改用 Setter 注入或 @Lazy(延迟注入)
// ② prototype 作用域的循环依赖 → 不会用缓存
//    解决:改成单例或重新设计

// Spring 解决循环依赖的前提:
//   → 单例 Bean
//   → Setter/字段注入(不是构造器注入)

模块二:Spring AOP

2.1 AOP 核心概念

复制代码
AOP(面向切面编程)= 把横切关注点(日志、事务、权限)从业务代码中抽离

核心术语:
  Aspect(切面)    = 横切逻辑 + 切点
  JoinPoint(连接点)= 能插入切面的位置(方法执行)
  Pointcut(切点)   = 匹配连接点的表达式
  Advice(通知)     = 在切点做什么、什么时候做
    @Before       → 方法执行前
    @After        → 方法执行后(无论是否异常)
    @AfterReturning → 方法正常返回后
    @AfterThrowing  → 方法抛异常后
    @Around       → 环绕(最强大,手动调 joinPoint.proceed())
  Weaving(织入)    = 将切面应用到目标对象(编译期/类加载期/运行期)

2.2 JDK 动态代理 vs CGLIB

java 复制代码
// ═══════════════════════════════════════
// JDK 动态代理
// ═══════════════════════════════════════
// 原理:实现目标类的接口 → 生成代理类 $Proxy0 extends Proxy implements Interface
// 要求:目标类必须有接口
// 创建:Proxy.newProxyInstance(classLoader, interfaces, invocationHandler)
//       每次调用代理方法 → InvocationHandler.invoke() → 可加通知

// ═══════════════════════════════════════
// CGLIB 代理
// ═══════════════════════════════════════
// 原理:继承目标类 → 生成子类 Enhancer extends TargetClass
//       通过 ASM 修改字节码
// 要求:目标类不能是 final(final 类不能继承)
//       方法不能是 final(final 方法不能重写)
// 创建:Enhancer.create(targetClass, methodInterceptor)

// ═══════════════════════════════════════
// Spring AOP 的选择策略
// ═══════════════════════════════════════
// Spring Boot 1.x:默认 JDK 动态代理
// Spring Boot 2.x+:默认 CGLIB(即使有接口也用 CGLIB)
//                   配置 spring.aop.proxy-target-class=true(默认)
// 手动指定:@EnableAspectJAutoProxy(proxyTargetClass = true) → CGLIB

2.3 @Transactional 失效的 6 种场景(面试必问!)

java 复制代码
// ═══════════════════════════════════════
// 场景 1:方法不是 public(最常见!)
// ═══════════════════════════════════════
@Transactional
private void doSomething() {}  // ❌ 私有方法,代理对象调不到

// ═══════════════════════════════════════
// 场景 2:同类方法调用(this 调用绕过代理)
// ═══════════════════════════════════════
@Service
public class UserService {
    public void methodA() {
        this.methodB();  // ❌ this 是原始对象,不是代理对象!
    }
    @Transactional
    public void methodB() {}  // 事务失效!
}
// 解决:注入自己 @Autowired private UserService self; → self.methodB();

// ═══════════════════════════════════════
// 场景 3:异常被 try-catch 吞掉
// ═══════════════════════════════════════
@Transactional
public void save() {
    try {
        // 数据库操作
        int i = 1 / 0;  // 抛出 RuntimeException
    } catch (Exception e) {
        log.error("出错了", e);  // ❌ 吞掉异常,Spring 感知不到 → 不回滚!
    }
}
// 解决:catch 中手动抛出异常 或 设置 rollbackFor

// ═══════════════════════════════════════
// 场景 4:rollbackFor 设置错误
// ═══════════════════════════════════════
@Transactional  // 默认只回滚 RuntimeException 和 Error
public void save() throws Exception {
    throw new Exception("检查异常");  // ❌ 不会回滚!
}
// 解决:@Transactional(rollbackFor = Exception.class)

// ═══════════════════════════════════════
// 场景 5:数据库引擎不支持事务
// ═══════════════════════════════════════
// MyISAM 不支持事务 → 怎么配置 @Transactional 都没用 → 用 InnoDB

// ═══════════════════════════════════════
// 场景 6:多线程调用
// ═══════════════════════════════════════
@Transactional
public void save() {
    new Thread(() -> {
        mapper.insert(data);  // ❌ 新线程不在当前事务中
    }).start();
}

2.4 事务传播行为(7 种)

传播行为 当前有事务 当前无事务 典型场景
REQUIRED(默认) 加入当前事务 新建事务 大多数场景
REQUIRES_NEW 挂起当前事务,新建 新建事务 日志记录(独立提交)
SUPPORTS 加入当前事务 不开启事务 查询
NOT_SUPPORTED 挂起当前事务,非事务运行 非事务运行 不需要事务的操作
MANDATORY 加入当前事务 抛异常 必须在事务中
NEVER 抛异常 非事务运行 必须在非事务中
NESTED 创建嵌套事务(Savepoint) 新建事务 部分回滚

模块三:Spring Boot

3.1 @SpringBootApplication 拆解

java 复制代码
@SpringBootApplication
// = @SpringBootConfiguration   ← 等同于 @Configuration,标记这是一个配置类
// + @EnableAutoConfiguration   ← 自动配置的核心!
// + @ComponentScan             ← 扫描当前包及子包的组件

// ═══════════════════════════════════════
// @EnableAutoConfiguration 的奥秘
// ═══════════════════════════════════════
@EnableAutoConfiguration
// = @AutoConfigurationPackage  ← 注册当前包路径(给 JPA 等用的)
// + @Import(AutoConfigurationImportSelector.class)

// AutoConfigurationImportSelector:
//   1. 从 META-INF/spring.factories(老版)
//      或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(新版)
//      中读取所有自动配置类的全限定名
//   2. 每个自动配置类上都有 @ConditionalOnXxx 注解
//   3. 满足条件 → 加载配置 → 创建对应的 Bean
//   4. 不满足 → 跳过

// 例子:DataSourceAutoConfiguration
// @ConditionalOnClass(DataSource.class)  ← classpath 中有 DataSource 才生效
// @ConditionalOnMissingBean(DataSource.class)  ← 用户没自定义 DataSource 才自动创建

3.2 starter 机制

复制代码
一个 starter = 一个 JAR 包,包含:
  → 所依赖的库(pom.xml 中声明为传递依赖)
  → 自动配置类(AutoConfiguration)
  → spring.factories / AutoConfiguration.imports 文件

命名规范:
  官方:spring-boot-starter-xxx(如 spring-boot-starter-web)
  第三方:xxx-spring-boot-starter(如 mybatis-spring-boot-starter)

自定义 starter 要点:
  ① 写一个配置类,用 @Bean 创建需要自动配置的对象
  ② 用 @ConditionalOnXxx 控制生效条件
  ③ 在 AutoConfiguration.imports 中注册配置类
  ④ @ConfigurationProperties(prefix = "my.starter") 读取 application.yml 配置

3.3 配置文件加载优先级(高到低)

复制代码
1. 命令行参数(--server.port=8080)
2. SPRING_APPLICATION_JSON 环境变量
3. OS 环境变量(SPRING_SERVER_PORT)
4. application-{profile}.yml(外部 jar 包外)
5. application-{profile}.yml(jar 包内)
6. application.yml(外部)
7. application.yml(内部)
8. @PropertySource 导入的配置

外部 > 内部,带 profile > 不带 profile,命令行 > 一切

模块四:Spring MVC

4.1 DispatcherServlet 完整请求流程

复制代码
用户请求 /user/123
      │
      ▼
┌──────────────┐
│ 过滤器链       │ ← Filter(不是 Spring MVC 的一部分,是 Servlet 规范)
└──────┬───────┘
       │
       ▼
┌──────────────────┐
│ DispatcherServlet │ ← Spring MVC 的核心前端控制器
└──────┬───────────┘
       │
       ▼
① HandlerMapping:找处理器
   "根据 /user/123 → UserController.getUser()"
       │
       ▼
② HandlerAdapter:执行处理器
   反射调用 getUser(123),返回 ModelAndView 或 @ResponseBody 对象
       │
       ▼
③ [拦截器 postHandle]
       │
       ▼
④ ViewResolver:解析视图
   将逻辑视图名 "user" 解析为 /WEB-INF/views/user.jsp
   如果是 @ResponseBody → 走 HttpMessageConverter → 写 JSON 到响应
       │
       ▼
⑤ 渲染视图 / 写响应体
       │
       ▼
⑥ [拦截器 afterCompletion]

4.2 拦截器 vs 过滤器 vs AOP

维度 过滤器 (Filter) 拦截器 (Interceptor) AOP
规范 Servlet 规范 Spring MVC Spring
容器 Servlet 容器管理 Spring 容器管理 Spring 容器管理
范围 所有请求 仅 DispatcherServlet 处理的请求 Spring Bean 的方法
能力 只能操作 Request/Response 可访问 Handler(Controller)+ ModelAndView 可访问方法参数和返回值
粒度 URL 级别 URL 级别 方法级别

模块五:MyBatis

5.1 核心执行流程

复制代码
SqlSession(门面)
  │
  ▼
Executor(执行器)
  ├── SimpleExecutor   ← 每次新 PreparedStatement(默认)
  ├── ReuseExecutor    ← 复用 PreparedStatement
  └── BatchExecutor    ← 批量操作
  │
  ▼
StatementHandler(语句处理器)
  ├── RoutingStatementHandler(路由)
  ├── SimpleStatementHandler
  └── PreparedStatementHandler
  │
  ▼
ParameterHandler(参数处理)
  │
  ▼
TypeHandler(类型转换)
  │
  ▼
JDBC PreparedStatement → 数据库
  │
  ▼
ResultSetHandler(结果集映射)

5.2 一级缓存 vs 二级缓存

维度 一级缓存(Local Cache) 二级缓存(Second Level Cache)
作用域 SqlSession 级别 Mapper 级别(Namespace)
生命周期 随 SqlSession 关闭而清除 应用级别
默认开启
清除 update/delete/insert 后自动清除 同左 + 可定时清除
问题 不同 SqlSession 间缓存不一致 脏读风险,分布式需额外处理

5.3 #{} vs ${}(SQL 注入核心)

xml 复制代码
<!-- #{}:预编译占位符 → 安全! -->
<select id="getUser" resultType="User">
    SELECT * FROM users WHERE name = #{name}
</select>
<!-- 编译为:SELECT * FROM users WHERE name = ?  → 参数安全绑定 -->

<!-- ${}:字符串替换 → 危险!SQL 注入风险! -->
<select id="getUser" resultType="User">
    SELECT * FROM users ORDER BY ${column}
</select>
<!-- 直接拼接:SELECT * FROM users ORDER BY name -->
<!-- 如果 column = "name; DROP TABLE users;" → 灾难 -->
java 复制代码
// ${} 的唯一合法场景:
// ① 动态表名/列名(ORDER BY / GROUP BY 的列名)
// ② LIKE 模糊查询(但 #{} + CONCAT('%', #{keyword}, '%') 更好)
// 其他所有场景一律用 #{}

面试题精选(10 道)

Q1. Spring IOC 的理解?Bean 的生命周期?(字节/阿里/美团 最高频)

标准回答

IOC(控制反转)把对象的创建和管理交给 Spring 容器,通过 DI(依赖注入)将依赖注入给使用方。

Bean 生命周期:实例化 → 属性注入 → Aware 回调 → BeanPostProcessor 前置处理 → @PostConstruct → InitializingBean → init-method → BeanPostProcessor 后置处理(AOP 代理在此生成!)→ 就绪 → 容器关闭时 @PreDestroy → DisposableBean → destroy-method。

最精简记忆:创建 → 注入 → 初始化前后处理 → 就绪 → 销毁。

Q2. Spring 怎么解决循环依赖?为什么用三级缓存?(阿里/字节 超高频)

标准回答

Spring 通过三级缓存解决单例 Bean 的 Setter/字段注入的循环依赖。一级缓存存成品 Bean,二级缓存存半成品,三级缓存存 ObjectFactory(Lambda)。

流程:A 和 B 互相依赖 → A 实例化后把 ObjectFactory 放入三级缓存 → 发现需要 B → B 实例化 → B 需要 A → 从三级缓存获取 A 的 ObjectFactory → 调用 getObject() 获取 A 的半成品(此处判断是否需 AOP 代理)→ 移入二级缓存 → B 注入 A 完成后放入一级缓存 → A 注入完整的 B 后也放入一级缓存。

为什么需要三级而非两级?因为 AOP。二级存对象则无法在后续得知是否需要代理。三级存 Lambda,getObject() 内部会判断并返回正确的版本(代理或原始对象)。

Q3. @Transactional 失效的场景?(阿里/美团/字节 高频)

标准回答

六种:① 方法非 public(代理调不到);② 同类方法调用 this.method()(绕过了代理对象);③ try-catch 吞掉异常(Spring 感知不到);④ rollbackFor 未正确设置(默认只回滚 RuntimeException,检查异常不回滚);⑤ 数据库引擎不支持事务(MyISAM);⑥ 多线程调用(新线程不在原事务中)。

Q4. Spring Boot 自动配置原理?(阿里/字节 高频)

标准回答

@SpringBootApplication 包含 @EnableAutoConfiguration → @Import(AutoConfigurationImportSelector) → 读取 META-INF/spring/...AutoConfiguration.imports 文件 → 加载 N 个自动配置类 → 每个类上都有 @ConditionalOnXxx 条件注解 → 满足条件则创建 Bean。

例如 DataSourceAutoConfiguration:@ConditionalOnClass(DataSource.class) 检查 classpath,@ConditionalOnMissingBean 检查用户是否已自定义,两者都满足才自动创建数据源。

Q5. Spring AOP 的原理?JDK 动态代理和 CGLIB 区别?(阿里/美团)

标准回答

AOP 通过代理模式将横切逻辑(日志/事务/权限)织入目标方法。JDK 动态代理要求目标类有接口,生成 Proxy 子类实现接口,InvocationHandler 拦截调用。CGLIB 通过 ASM 修改字节码,生成目标类的子类来代理,不能代理 final 类和方法。

Spring Boot 2.x+ 默认使用 CGLIB(即使有接口)。AOP 代理生成发生在 Bean 生命周期的 BeanPostProcessor 后置处理阶段。

Q6. Spring MVC 的请求处理流程?(字节/阿里)

标准回答

DispatcherServlet 统一接收请求 → HandlerMapping 找到对应的 Controller 方法 → HandlerAdapter 执行 → Controller 返回 ModelAndView 或 @ResponseBody 对象 → ViewResolver 解析视图 或 HttpMessageConverter 写 JSON → 响应返回。

拦截器有 preHandle(Controller 前)、postHandle(Controller 后、视图前)、afterCompletion(视图后)三个切入时机。

Q7. MyBatis #{} 和 ${} 的区别?(阿里/美团 高频)

标准回答

#{} 是预编译占位符(?),安全防 SQL 注入,自动加引号。{} 是字符串直接拼接,有 SQL 注入风险,只在动态表名/列名/ORDER BY 等必须拼接的场景使用。开发规范:能用 #{} 绝不用 {}。

Q8. Spring 事务传播行为 REQUIRED 和 REQUIRES_NEW 的区别?(字节/阿里)

标准回答

REQUIRED(默认)有事务则加入,没有则创建。REQUIRES_NEW 不管当前有没有事务都创建新事务,有则挂起当前事务。典型场景:订单创建(REQUIRED) + 日志记录(REQUIRES_NEW),日志写入独立提交,不受订单事务回滚的影响。

Q9. BeanFactory 和 ApplicationContext 区别?(腾讯/阿里)

标准回答

BeanFactory 是底层 IOC 容器,懒加载(首次 getBean 才初始化),功能简单。ApplicationContext 继承 BeanFactory,预加载(启动时初始化所有单例 Bean),提供 AOP、事件发布、国际化、资源加载等企业功能。日常开发只用 ApplicationContext。

Q10. MyBatis 一级缓存和二级缓存的区别?(美团/字节)

标准回答

一级缓存是 SqlSession 级别,默认开启,同 Session 内相同查询走缓存,update/delete/insert 后清空。二级缓存是 Mapper 级别(跨 Session),需手动开启,所有 Session 共享,有脏读风险。生产环境慎用二级缓存(分布式场景建议用 Redis 等分布式缓存替代)。


📊 今日知识图谱

复制代码
Spring 全家桶 DAY 11
│
├── Spring IOC
│   ├── Bean 生命周期 12 步(重点:后置处理生成 AOP 代理)
│   ├── 三级缓存:一级(成品)/二级(半成品)/三级(ObjectFactory)
│   │   └── 为什么三级?AOP 代理的不确定性!
│   └── 循环依赖前提:单例 + Setter/字段注入(构造器不行)
│
├── Spring AOP
│   ├── JDK 动态代理(接口) vs CGLIB(继承, Spring Boot 2.x+ 默认)
│   └── @Transactional 失效 6 大场景(非public/this调用/吞异常最常考)
│
├── Spring Boot
│   ├── @SpringBootApplication = @Config + @EnableAutoConfig + @ComponentScan
│   └── 自动配置:读取 .imports → @ConditionalOnXxx → 创建 Bean
│
├── Spring MVC
│   ├── DispatcherServlet → HandlerMapping → HandlerAdapter → ViewResolver
│   └── Filter(最外层) vs Interceptor(Spring MVC) vs AOP(方法级)
│
└── MyBatis
    ├── SqlSession → Executor → StatementHandler → JDBC
    ├── #{}预编译(安全) vs ${}字符串拼接(SQL注入风险)
    └── 一级缓存(SqlSession,默认开启) vs 二级缓存(Mapper,慎用)

🔜 明日预告

Day 12 --- MySQL + Redis 深度拆解

  • B+ 树索引 + 聚簇 vs 非聚簇 + 联合索引最左前缀 + 索引失效 10 场景
  • MVCC(ReadView + Undo Log)+ 事务隔离级别 + 锁(Record/Gap/Next-Key)
  • SQL 优化:explain 分析 + 覆盖索引 + 索引下推 + 分库分表
  • Redis 5 种结构底层(SDS/ziplist/skiplist)+ 缓存穿透/击穿/雪崩
  • 持久化 RDB vs AOF vs 混合 + 分布式锁(setnx+Lua)
  • 10 道 MySQL + Redis 高频真题

💡 速通心法:Spring 面试三座大山------IOC 的循环依赖(三级缓存 + 为什么不是两级)、AOP 的 @Transactional 失效(6 种场景必须倒背如流)、Boot 的自动配置(读 imports → @Conditional 判断 → 创建 Bean)。这三个讲清楚,Spring 面试就过了一半。另一半是 MyBatis 的 ${} SQL 注入风险和缓存对比。

相关推荐
吴声子夜歌2 小时前
MongoDB 4.x——SpringBoot框架整合
数据库·spring boot·mongodb
snow@li2 小时前
Spring Boot:项目服务器完整部署教程(零基础可直接实操)
服务器·spring boot·后端
万亿少女的梦1683 小时前
基于Spring Boot、Java与MySQL的网络订餐系统设计与实现
java·spring boot·mysql·系统设计·网络订餐
鱟鲥鳚12 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
腾渊信息科技公司14 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
憧憬成为web高手15 小时前
皮卡丘靶场速通--sql 2
数据库·sql·mybatis
隔窗听雨眠18 小时前
Spring Boot在云原生时代的编程范式革新研究
spring boot·后端·云原生
其美杰布-富贵-李20 小时前
Spring Boot 工程开发全流程说明
java·spring boot·后端
dear_bi_MyOnly21 小时前
【SpringBoot配置文件】
java·spring boot·后端·学习·spring·java-ee·学习方法