Spring容器管理着Bean,业务代码操作MySQL需要事务保证一致性,高并发下用线程池处理请求,日志文件落地通过IO流写入磁盘

发布时间:2026/7/30 2:27:26

Spring容器管理着Bean,业务代码操作MySQL需要事务保证一致性,高并发下用线程池处理请求,日志文件落地通过IO流写入磁盘 # Java后端极速唤醒Day3-Day6 核心知识整合资料 本文整合了《Java后端极速唤醒计划》中 **Day 3多线程进阶**、**Day 4IO流与文件操作**、**Day 5MySQL** 和 **Day 6Spring核心** 的全部核心知识点。内容密集适合面试前集中复习和知识唤醒。---## 第一部分多线程进阶Day 3### 一、常见的锁策略面试基础题锁策略是面试中考察并发编程深度的基础以下是几种常见的分类维度| 锁类型 | 核心思想 | 适用场景 | Java中的体现 || :--- | :--- | :--- | :--- || **乐观锁** | 假设数据一般不会冲突不加锁更新时检查版本号 | 读多写少 | AtomicIntegerCAS、版本号机制 || **悲观锁** | 假设数据一定会被修改每次操作都加锁 | 写多读少 | synchronized、ReentrantLock || **重量级锁** | 依赖操作系统互斥量mutex有用户态/内核态切换 | 锁竞争激烈 | synchronized重量级状态 || **轻量级锁** | 通过CAS自旋实现不涉及内核态切换 | 锁竞争不激烈 | synchronized轻量级状态、自旋锁 || **自旋锁** | 抢锁失败时不放弃CPU循环重试 | 锁持有时间短 | CAS自旋 || **挂起等待锁** | 抢锁失败时放弃CPU进入阻塞状态 | 锁持有时间长 | Object.wait()、重量级锁 || **公平锁** | 遵循先来后到按等待顺序获取锁 | 避免线程饥饿 | new ReentrantLock(true) || **非公平锁** | 抢占式不按等待顺序 | 吞吐量更高 | synchronized、new ReentrantLock(false)默认 || **可重入锁** | 同一个线程可以多次获取同一把锁 | 递归调用、嵌套锁 | synchronized、ReentrantLock || **不可重入锁** | 同一线程不能重复获取 | — | 自定义锁理论存在 || **读写锁** | 读锁共享、写锁互斥读读不互斥 | 读多写少 | ReentrantReadWriteLock | **面试重点**为什么 synchronized 是**非公平锁**因为操作系统线程调度本身就是随机的Java没有额外维护等待队列的顺序。---### 二、CASCompare And Swap原理#### 2.1 什么是CASCAS是一条CPU原子指令完成 **“比较-交换”** 两个动作。伪代码如下java// 这不是真实代码是逻辑示意boolean CAS(address, expectedValue, newValue) {if (*(address) expectedValue) {*(address) newValue;return true;}return false;}- **V**要修改的内存地址变量- **A**旧的预期值线程之前读取到的值- **B**新的要写入的值#### 2.2 CAS的应用**① 原子类AtomicInteger**javaAtomicInteger count new AtomicInteger(0);count.incrementAndGet(); // 相当于 i无锁实现比synchronized快**② 自旋锁的实现**javapublic class SpinLock {private AtomicReferenceThread owner new AtomicReference();public void lock() {while (!owner.compareAndSet(null, Thread.currentThread())) {// 自旋等待}}}#### 2.3 ABA问题与解决方案- **ABA问题**变量从A→B→ACAS认为没变但实际上已经变过。- **解决方案**引入**版本号**。java// 使用AtomicStampedReference带版本号的原子引用AtomicStampedReferenceString ref new AtomicStampedReference(A, 1);boolean success ref.compareAndSet(A, B, 1, 2);---### 三、JUCjava.util.concurrent常用工具#### 3.1 ReentrantLock可重入锁**与synchronized的对比高频面试**| 维度 | synchronized | ReentrantLock || :--- | :--- | :--- || 实现 | JVM内置关键字C实现 | Java标准库类 || 释放锁 | 自动释放 | 必须手动unlock()通常放在finally中 || 等待超时 | 不支持 | 支持tryLock(timeout) || 公平锁 | 不支持非公平 | 支持构造传参true || 等待唤醒 | wait()/notify()随机唤醒 | Condition精准唤醒指定线程 || 适用场景 | 锁竞争不激烈 | 锁竞争激烈、需要灵活控制 |**使用模板**javaReentrantLock lock new ReentrantLock();lock.lock();try {// 业务逻辑} finally {lock.unlock(); // 必须手动释放}#### 3.2 Semaphore信号量- **作用**控制同时访问某个资源的**并发线程数**限流器。- **类比**停车场门口的车位显示屏“剩余车位”。javaSemaphore semaphore new Semaphore(5); // 最多5个线程同时执行semaphore.acquire(); // P操作申请资源计数-1为0时阻塞// 业务逻辑semaphore.release(); // V操作释放资源计数1#### 3.3 CountDownLatch倒计时器- **作用**等待**多个线程**全部执行完毕后再继续执行。- **类比**运动会裁判要等所有运动员都到达终点才能公布成绩。javaCountDownLatch latch new CountDownLatch(10);for (int i 0; i 10; i) {new Thread(() - {// 执行业务latch.countDown(); // 计数-1}).start();}latch.await(); // 阻塞等待计数变为0System.out.println(所有线程执行完毕);#### 3.4 Callable FutureTask- **Callable**类似Runnable但**有返回值**且可以抛出异常。- **FutureTask**用于异步获取Callable的执行结果。javaCallableInteger callable () - {int sum 0;for (int i 1; i 1000; i) sum i;return sum;};FutureTaskInteger futureTask new FutureTask(callable);new Thread(futureTask).start();Integer result futureTask.get(); // 阻塞等待结果返回System.out.println(result);---### 四、synchronized的底层优化锁升级JDK 1.6对synchronized做了大量优化锁的升级过程是**不可逆的**单向**无锁 → 偏向锁 → 轻量级锁自旋锁 → 重量级锁**#### 4.1 偏向锁Biased Locking- **思想**一个锁被线程A获取后直接在对象头中打上标记“属于线程A”。后续A再来获取不需要做任何同步操作。- **场景**实际开发中很多锁从头到尾只有一个线程访问。- **比喻**情侣不领结婚证但对外宣称“这是我对象”杜绝其他人想法。#### 4.2 轻量级锁Lightweight Locking- 当线程B尝试获取偏向锁时偏向锁撤销升级为轻量级锁。- **实现**基于**自旋CAS**不阻塞线程避免内核态切换。- **自适应自旋**如果上次自旋成功这次多自旋几次如果上次失败这次少自旋。#### 4.3 重量级锁Heavyweight Locking- 当自旋次数达到阈值仍未获取到锁升级为重量级锁。- **实现**依赖操作系统底层mutex线程阻塞进入等待队列涉及用户态/内核态切换开销极大。#### 4.4 额外的优化锁消除与锁粗化| 优化 | 解释 || :--- | :--- || **锁消除** | JIT编译器检测到不可能存在锁竞争如单线程中使用的StringBuffer直接去掉锁。 || **锁粗化** | 将连续的多次加锁/解锁合并为一次减少操作次数如循环中反复加锁。 |---### 五、线程池ThreadPoolExecutor#### 5.1 创建线程池的几种方式| 方法Executors工厂类 | 含义 | 风险 || :--- | :--- | :--- || newFixedThreadPool(n) | 固定核心线程数 | 队列无界可能OOM || newCachedThreadPool() | 动态扩容空闲线程存活60s | 最大线程数Integer.MAX_VALUE可能撑爆 || newSingleThreadExecutor() | 单线程线程池 | 队列无界 || newScheduledThreadPool(n) | 支持定时/延迟任务 | — | **阿里巴巴开发规范**禁止使用Executors直接创建线程池必须使用ThreadPoolExecutor手动指定参数规避资源耗尽风险。#### 5.2 ThreadPoolExecutor七大核心参数javanew ThreadPoolExecutor(int corePoolSize, // 核心线程数正式员工int maximumPoolSize, // 最大线程数正式临时工long keepAliveTime, // 临时工空闲存活时间TimeUnit unit, // 时间单位BlockingQueueRunnable workQueue, // 任务阻塞队列ThreadFactory threadFactory, // 线程工厂RejectedExecutionHandler handler // 拒绝策略)#### 5.3 任务提交流程核心机制提交任务↓核心线程数已满 → 否 → 创建核心线程执行↓ 是阻塞队列已满 → 否 → 任务入队等待↓ 是最大线程数已满 → 否 → 创建临时线程执行↓ 是执行拒绝策略#### 5.4 四种拒绝策略| 策略 | 行为 || :--- | :--- || AbortPolicy默认 | 直接抛出RejectedExecutionException || CallerRunsPolicy | 让调用者线程提交任务的线程自己执行该任务 || DiscardOldestPolicy | 丢弃队列中最老等待最久的任务然后重新提交 || DiscardPolicy | 直接丢弃新提交的任务不抛异常 |---## 第二部分文件操作与IO流Day 4### 一、File类文件/目录的元信息操作java.io.File 是对文件或目录路径名的抽象表示。**注意创建File对象并不代表磁盘上真正存在该文件。**#### 1.1 常用构造方法javaFile file1 new File(test.txt);File file2 new File(D:\\data, test.txt);#### 1.2 常用方法分类记忆| 类别 | 方法 | 说明 || :--- | :--- | :--- || **判断** | exists() | 文件是否存在 || | isDirectory() | 是否为目录 || | isFile() | 是否为普通文件 || **获取** | getName() | 获取文件名 || | getPath() | 获取路径构造时的路径 || | getAbsolutePath() | 获取绝对路径 || | getParent() | 获取父目录路径 || **创建/删除** | createNewFile() | 创建文件原子操作 || | mkdir() | 创建单层目录 || | mkdirs() | 创建多层目录推荐 || | delete() | 删除文件/空目录 || | deleteOnExit() | 程序退出时删除临时文件 || **遍历** | listFiles() | 返回目录下的所有File对象递归遍历时可使用 |**示例递归扫描目录**javapublic void scanDir(File dir) {File[] files dir.listFiles();if (files null) return;for (File file : files) {if (file.isDirectory()) {scanDir(file);} else {System.out.println(file.getAbsolutePath());}}}---### 二、字节流InputStream / OutputStream#### 2.1 核心方法| InputStream | OutputStream || :--- | :--- || int read()读1个字节 | void write(int b)写1个字节 || int read(byte[] buf)读入字节数组 | void write(byte[] buf) || int read(byte[] buf, int off, int len) | void write(byte[] buf, int off, int len) || void close() | void close() || — | void flush()强制刷出缓冲 |#### 2.2 标准输入输出流java// 标准输入键盘InputStream in System.in;// 标准输出控制台OutputStream out System.out;#### 2.3 文件字节流FileInputStream / FileOutputStream**读取文件的两种方式对比**java// 方式1单字节读取IO次数多效率低try (InputStream is new FileInputStream(test.txt)) {int b;while ((b is.read()) ! -1) {System.out.print((char) b);}}// 方式2批量读取IO次数少效率高推荐try (InputStream is new FileInputStream(test.txt)) {byte[] buffer new byte[1024];int len;while ((len is.read(buffer)) ! -1) {System.out.write(buffer, 0, len);}} **记忆**read() 返回 -1 表示文件读取结束。---### 三、字符流Reader / Writer字节流处理二进制数据字符流处理文本数据解决了编码问题。#### 3.1 常见字符流| 输入流Reader | 输出流Writer || :--- | :--- || FileReader | FileWriter || InputStreamReader字节→字符可指定编码 | OutputStreamWriter字符→字节 |#### 3.2 字符流读取文本标准写法javatry (InputStream is new FileInputStream(test.txt);InputStreamReader isr new InputStreamReader(is, UTF-8);Scanner scanner new Scanner(isr)) {while (scanner.hasNextLine()) {String line scanner.nextLine();System.out.println(line);}}#### 3.3 PrintWriter最像C语言printf的用法javatry (OutputStream os new FileOutputStream(output.txt);OutputStreamWriter osw new OutputStreamWriter(os, UTF-8);PrintWriter writer new PrintWriter(osw)) {writer.println(你好世界); // 自动加换行writer.printf(年龄: %d\n, 25); // 格式化输出writer.flush();} **注意**PrintWriter 的 print/println/printf 都不会自动刷出必须手动调用 flush()。---### 四、文件拷贝典型IO练习javapublic void copyFile(String srcPath, String destPath) throws IOException {try (InputStream is new FileInputStream(srcPath);OutputStream os new FileOutputStream(destPath)) {byte[] buffer new byte[1024];int len;while ((len is.read(buffer)) ! -1) {os.write(buffer, 0, len);}os.flush();}}---## 第三部分MySQLDay 5### 一、索引底层数据结构B树#### 1.1 MySQL为什么用B树而非B树、红黑树| 数据结构 | 高度 | 磁盘IO次数 | 范围查询 | MySQL选择 || :--- | :--- | :--- | :--- | :--- || 红黑树 | 高几十层 | 多 | 弱 | ❌ || B树 | 低 | 少 | 需要中序遍历效率低 | ❌ || **B树** | **低3~4层** | **少** | **叶子节点双向链表天然支持** | ✅ |#### 1.2 B树核心特点1. **非叶子节点只存键索引值 指针不存数据** → 一页16KB能放更多索引树更矮。2. **所有数据都存在叶子节点** → 查询稳定必须到叶子节点。3. **叶子节点形成有序双向链表** → 范围查询极快BETWEEN、、。#### 1.3 索引分类| 分类 | 说明 || :--- | :--- || **聚簇索引**主键索引 | 叶子节点存**完整行数据**。InnoDB中主键即聚簇索引。 || **二级索引**非主键索引 | 叶子节点存**主键值**回表需根据主键再查一次聚簇索引。 || **覆盖索引** | 查询的字段刚好在索引树上就能全部拿到**不需要回表**如select id from table where namexxxname字段有索引。 |#### 1.4 最左前缀匹配原则联合索引 (a, b, c) 会按 a→b→c 的顺序构建B树。以下情况**命中**索引- WHERE a 1- WHERE a 1 AND b 2- WHERE a 1 AND b 2 AND c 3以下情况**不命中**索引- WHERE b 2 AND c 3跳过了a- WHERE c 3跳过了a和b **坑**WHERE a 1 AND c 3 只会用到a的索引c无法利用因为b缺失导致索引树中断。---### 二、事务与隔离级别#### 2.1 ACID四大特性| 特性 | 含义 || :--- | :--- || **原子性A** | 事务要么全部成功要么全部回滚 || **一致性C** | 事务执行前后数据状态保持一致 || **隔离性I** | 多个事务并发执行互不干扰 || **持久性D** | 事务提交后数据永久保存即使宕机 |#### 2.2 并发事务带来的问题| 问题 | 表现 || :--- | :--- || **脏读Dirty Read** | 读到另一个事务**未提交**的数据回滚后数据就没了 || **不可重复读Non-Repeatable Read** | 同一事务内两次读取同一条记录结果不同其他事务修改了 || **幻读Phantom Read** | 同一事务内两次查询结果集条数不同其他事务插入了新行 |#### 2.3 四种隔离级别| 隔离级别 | 脏读 | 不可重复读 | 幻读 | MySQL默认 || :--- | :--- | :--- | :--- | :--- || **读未提交Read Uncommitted** | 可能 | 可能 | 可能 | ❌ || **读已提交Read CommittedRC** | 不可能 | 可能 | 可能 | ❌ || **可重复读Repeatable ReadRR** | 不可能 | 不可能 | **InnoDB可以解决** | ✅ 默认 || **串行化Serializable** | 不可能 | 不可能 | 不可能 | ❌ |#### 2.4 MySQL如何解决幻读RR隔离级别下1. **间隙锁Gap Lock**当执行范围查询时锁定查询范围内的**间隙**阻止其他事务插入。2. **MVCC多版本并发控制**快照读SELECT读的是当前事务开始时的“快照版本”不受其他事务插入影响。---### 三、MVCC机制高频面试#### 3.1 三个核心隐式字段InnoDB每行记录除了业务数据外还有三个隐藏字段| 字段 | 含义 || :--- | :--- || DB_TRX_ID | 最近修改该行的事务ID || DB_ROLL_PTR | 回滚指针指向Undo Log中该行的上一个版本 || DB_ROW_ID | 行ID如果没有主键InnoDB会自动生成聚簇索引 |#### 3.2 ReadView读视图ReadView包含四个关键信息- m_ids生成ReadView时活跃未提交的事务ID列表- min_trx_idm_ids中的最小值- max_trx_id下一个要分配的事务ID- creator_trx_id当前事务的ID#### 3.3 可见性判定规则当读取一行数据时根据该行的 DB_TRX_ID 判断1. 若 DB_TRX_ID creator_trx_id → 本事务修改的可见。2. 若 DB_TRX_ID min_trx_id → 修改该行的事务已提交可见。3. 若 DB_TRX_ID max_trx_id → 修改该行的事务在ReadView生成之后才开启不可见。4. 若 min_trx_id DB_TRX_ID max_trx_id- 若 DB_TRX_ID in m_ids → 事务未提交不可见顺着Undo Log找上个版本。- 若 DB_TRX_ID not in m_ids → 事务已提交可见。 **RC与RR的区别**RC每次查询都会生成新的ReadViewRR只在第一次查询时生成ReadView后续复用。所以RR能避免不可重复读。---### 四、SQL优化与EXPLAIN#### 4.1 慢查询优化思路1. 通过慢查询日志找到慢SQL。2. 使用 EXPLAIN 查看执行计划。3. 重点关注 type、possible_keys、key、rows、Extra。**EXPLAIN中type级别从优到差**system const eq_ref ref range index ALL- 至少达到 range 级别最好达到 ref。- ALL全表扫描是必须优化的目标。**Extra列常见优化信息**- Using index使用了覆盖索引无需回表最优。- Using where使用了WHERE过滤。- Using filesort需要额外排序应优化索引避免。- Using temporary使用了临时表如DISTINCT、GROUP BY无索引时。#### 4.2 索引失效场景记忆口诀**“三列函数”**1. **违反最左前缀法则**联合索引跳过了第一列。2. **在索引列上进行计算或使用函数**如 WHERE age 1 20。3. **隐式类型转换**如 WHERE phone 123phone是varchar传入int。4. **使用 LIKE %xxx**百分号在开头索引失效LIKE xxx% 可以走索引。5. **使用 OR 连接非索引列**如果OR的一侧没有索引整个查询不走索引。---## 第四部分Spring核心Day 6### 一、IoC控制反转与DI依赖注入#### 1.1 IoC概念控制权从**程序自身**转移到**Spring容器**。对象不再由程序员new而是由Spring容器创建、管理和装配。#### 1.2 DI三种注入方式| 方式 | 优点 | 缺点 | 推荐度 || :--- | :--- | :--- | :--- || **构造器注入**Constructor | 不可变final、强依赖、单元测试友好 | 参数过多时代码冗余 | ⭐⭐⭐⭐⭐官方推荐 || **Setter注入** | 灵活支持部分注入 | 可变容易忘记注入 | ⭐⭐ || **Field注入**Autowired直接打在字段上 | 代码最简洁 | 无法设置final对外部隐藏依赖测试需要反射 | ⭐⭐⭐日常常用但官方不推荐 |---### 二、Bean生命周期高频考点**完整流程10步**实例化构造方法↓设置属性值setter依赖注入↓执行Aware接口回调BeanNameAware、BeanFactoryAware等↓BeanPostProcessor前置处理postProcessBeforeInitialization↓执行初始化方法PostConstruct、InitializingBean、init-method↓BeanPostProcessor后置处理postProcessAfterInitialization← AOP代理发生在这里↓Bean准备就绪可正常使用↓容器关闭执行销毁方法PreDestroy、DisposableBean、destroy-method **面试高频**AOP的动态代理是在 **BeanPostProcessor的后置处理** 阶段生成的。---### 三、循环依赖与三级缓存#### 3.1 什么是循环依赖Class A {Autowired B b;}Class B {Autowired A a;}#### 3.2 Spring解决循环依赖的核心机制三级缓存| 缓存 | 名称 | 存储内容 | 作用 || :--- | :--- | :--- | :--- || **一级缓存** | singletonObjects | 完全初始化好的单例Bean成品 | 供外部获取使用 || **二级缓存** | earlySingletonObjects | 提前暴露的半成品Bean未完成属性注入 | 解决循环依赖引用 || **三级缓存** | singletonFactories | ObjectFactory工厂对象 | 生成代理对象的早期引用 |**核心流程A依赖BB依赖A**1. 创建A的实例通过无参构造→ 将A的ObjectFactory放入三级缓存。2. 填充A的属性发现需要B。3. 去单例池找B没有创建B的实例 → 将B的ObjectFactory放入三级缓存。4. 填充B的属性发现需要A。5. 从三级缓存获取A的ObjectFactory → 生成A的早期引用此时可能做AOP→ 放入二级缓存。6. B完成属性注入初始化完成 → 放入一级缓存。7. 回到A从一级缓存拿到B完成注入 → A初始化完成 → 放入一级缓存。 **为什么需要三级缓存而不是二级** 因为如果Bean被AOP代理需要提前生成代理对象。三级缓存存放工厂对象可以在**需要代理时才生成代理对象**而不是提前创建。这是为了处理AOP与循环依赖的共存问题。---### 四、AOP面向切面编程#### 4.1 核心概念| 术语 | 含义 || :--- | :--- || **JoinPoint连接点** | 程序执行过程中的某个点如方法调用 || **Pointcut切点** | 一组连接点的集合如execution(* com.service.*.*(..)) || **Advice通知** | 在切点上执行的增强逻辑Before、After、Around等 || **Aspect切面** | Pointcut Advice的组合相当于一个类 || **Weaving织入** | 将切面应用到目标对象的过程编译期、类加载期、运行期 |#### 4.2 五种通知类型javaBefore(execution(* com.service.*.*(..))) // 方法执行前After(execution(* com.service.*.*(..))) // 方法执行后无论是否异常AfterReturning(pointcut ..., returning res) // 方法正常返回后AfterThrowing(pointcut ..., throwing e) // 方法抛异常后Around(...) // 环绕通知最强可控制是否执行目标方法#### 4.3 动态代理的实现方式面试必问| 代理方式 | 要求 | 实现原理 | 性能 || :--- | :--- | :--- | :--- || **JDK动态代理** | 目标类**必须实现接口** | 生成一个实现了该接口的代理类 | 较新版本中性能接近CGLIB || **CGLIB** | 目标类**不要求实现接口**最终类不行 | 生成目标类的子类重写父类方法 | 较快 |**Spring如何选择**- 如果目标类实现了接口且接口不为空 → 默认使用JDK动态代理。- 如果目标类没有实现接口 → 使用CGLIB。- 可通过 EnableAspectJAutoProxy(proxyTargetClass true) 强制使用CGLIB。---### 五、Spring事务管理#### 5.1 事务传播行为7种重点记4种| 传播行为 | 含义 || :--- | :--- || **REQUIRED默认** | 当前有事务就加入没有就新建一个。 || **REQUIRES_NEW** | 总是新建一个事务。当前有事务则挂起。 || **SUPPORTS** | 当前有事务就加入没有就以非事务方式执行。 || **NOT_SUPPORTED** | 以非事务方式执行当前有事务则挂起。 || MANDATORY | 必须在一个已有事务中执行否则抛异常。 || NEVER | 必须在非事务中执行否则抛异常。 || NESTED | 在当前事务中开启嵌套事务子事务回滚不影响父事务。 |#### 5.2 Transactional失效场景面试杀手题| 场景 | 原因 || :--- | :--- || **方法不是public** | Spring事务代理只对public方法生效。 || **自调用同一个类内调用** | this.method() 绕过了代理对象没有事务增强。 || **异常被catch吞掉** | 事务只对未捕获的RuntimeException回滚。 || **数据源没有配置事务管理器** | — || **事务传播行为配置错误** | 如NOT_SUPPORTED会强行挂起事务。 |**自调用解决方案**javaServicepublic class UserService {Autowiredprivate UserService self; // 注入自身代理对象public void method1() {self.method2(); // 通过代理调用事务生效}Transactionalpublic void method2() { ... }}---### 六、Spring Boot自动装配原理#### 6.1 核心注解SpringBootApplication Configuration EnableAutoConfiguration ComponentScan#### 6.2 自动装配核心流程1. EnableAutoConfiguration 通过 Import(AutoConfigurationImportSelector.class) 导入选择器。2. AutoConfigurationImportSelector 读取 META-INF/spring.factories 文件或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsSpring Boot 2.7。3. 加载所有自动配置类如 DataSourceAutoConfiguration、WebMvcAutoConfiguration。4. 根据 Conditional 条件注解如 ConditionalOnClass、ConditionalOnMissingBean判断是否生效。5. 生成对应的Bean注入容器。#### 6.3 自定义Starter1. 创建一个自动配置类Configuration ConditionalOnClass。2. 在 resources/META-INF/spring.factories 中配置org.springframework.boot.autoconfigure.EnableAutoConfiguration\com.example.MyAutoConfiguration---## 总结四天复习要点速查表| 模块 | 核心必考点 | 面试频率 || :--- | :--- | :--- || **多线程进阶** | 锁策略乐观/悲观/自旋/读写、CAS与ABA、synchronized锁升级、线程池参数 | ⭐⭐⭐⭐⭐ || **IO与文件** | InputStream/OutputStream读写、字符流编码问题、File类递归遍历 | ⭐⭐⭐ || **MySQL** | B树索引、MVCC可见性、隔离级别、最左前缀、EXPLAIN分析 | ⭐⭐⭐⭐⭐ || **Spring核心** | Bean生命周期、三级缓存解决循环依赖、AOP代理选择、事务失效场景 | ⭐⭐⭐⭐⭐ |**一句话串联四天** *“Spring容器管理着BeanDay 6业务代码操作MySQLDay 5需要事务保证一致性高并发下用线程池Day 3处理请求日志文件落地通过IO流Day 4写入磁盘。”*复习完毕

相关新闻