[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f1b300lqgtfmoj":3,"$f250wz8h39yydc":8,"$f2sjsm7earac5z":29,"$fh8iy32231rt":33,"$f1yyf2gr7j29ha":44,"toc--1881800634-5-5":48},{"description":4,"domain":5,"id":6,"keywords":4,"title":7},"","api.kongjs.com",1,"默认",[9,20,24],{"children":10,"icon":4,"id":11,"linkType":12,"linkUrl":13,"parentId":14,"sort":15,"status":16,"target":17,"title":18,"visible":19},null,"447369447469600768","URL","\u002F","0",0,"1","_self","首页",true,{"children":10,"icon":4,"id":21,"linkType":12,"linkUrl":22,"parentId":14,"sort":15,"status":16,"target":17,"title":23,"visible":19},"447369693859794944","\u002Fnotes","笔记",{"children":10,"icon":4,"id":25,"linkType":26,"linkUrl":27,"parentId":14,"sort":15,"status":16,"target":17,"title":28,"visible":19},"447369977960976384","PAGE","\u002Fabout","关于我",{"category":10,"categoryId":10,"cover":10,"description":4,"fileId":10,"id":30,"publishAt":10,"tags":31,"title":32},"453169352129126400",[],"Spring面试核心知识",[34,37,40],{"children":10,"description":4,"id":35,"noteId":30,"parentId":14,"sort":15,"status":16,"title":36},"453169498883629056","Spring IOC、Bean注入、循环依赖、AOP、动态代理完整原理",{"children":10,"description":4,"id":38,"noteId":30,"parentId":14,"sort":6,"status":16,"title":39},"453169617112670208","Spring事务原理、传播机制、失效场景、分布式事务全套实现",{"children":10,"description":4,"id":41,"noteId":30,"parentId":14,"sort":42,"status":16,"title":43},"453169742979538944",2,"SpringBoot2\u002F3\u002F4自动装配原理、版本迭代详解",{"content":45,"contentType":46,"description":4,"title":36,"wordCount":47},"# Spring IOC、Bean注入、循环依赖、AOP、动态代理完整原理\n\n本文全覆盖 Spring 底层五大核心考点：**IOC容器原理、Bean生命周期、三种注入方式、三级缓存解决循环依赖、AOP底层原理、JDK\u002FCGLIB动态代理区别**，无废话、全面试高频、逻辑闭环、可直接背诵手撕面试。\n\n## 一、Spring IOC 核心原理\n\n### 1\\. IOC 概念（控制反转）\n\n**传统开发**：开发者主动 new 对象、管理依赖、控制生命周期（程序员主动）\n\n**IOC控制反转**：**将对象创建、依赖管理、生命周期控制权反转交给Spring容器**（容器主动）\n\n**DI依赖注入**：IOC的实现手段，容器自动给Bean赋值、注入依赖\n\n### 2\\. IOC 核心作用\n\n- 解耦：彻底消除硬编码 new 对象\n\n- 统一管理Bean生命周期\n\n- 自动依赖注入、自动解决依赖关系\n\n- 为AOP、事务、Spring全家桶提供底层支撑\n\n### 3\\. IOC 容器核心执行流程（必背）\n\nSpring 启动加载 Bean 完整流程：\n\n1. **资源加载、扫描配置**：加载xml\u002F注解配置、扫描包路径，得到Bean定义信息\n\n2. **解析Bean定义（BeanDefinition）**：不创建对象，仅解析类信息、属性、作用域、依赖，存入BeanDefinitionMap\n\n3. **Bean实例化**：单例Bean在容器启动阶段统一通过反射创建对象\n\n4. **依赖注入DI**：自动填充属性、注入依赖Bean\n\n5. **初始化前置后置**：Bean后置处理器、InitializingBean、init\\-method\n\n6. **完成初始化**：放入单例池，对外提供服务\n\n7. **容器关闭**：执行销毁方法\n\n### 4\\. Bean 完整生命周期（满分背诵）\n\n**扫描解析 → 实例化 → 依赖注入 → 初始化 → 就绪使用 → 销毁**\n\n```plain\nBean生命周期完整链路\n1. 解析配置生成 BeanDefinition\n2. 反射实例化对象（空对象）\n3. 依赖注入填充属性\n4. 执行BeanPostProcessor前置处理\n5. 执行InitializingBean \u002F init-method\n6. 执行BeanPostProcessor后置处理（AOP代理在此步生成）\n7. Bean就绪对外提供服务\n8. 容器关闭执行销毁方法\n\n```\n\n---\n\n## 二、Spring 三种依赖注入方式 \\& 区别\n\n### 1\\. 字段注入（@Autowired）\n\n- 直接注解在字段上，简洁方便\n\n- **底层原理**：反射暴力赋值\n\n- **弊端**：\n        \n\n    - 违反单一职责\n\n    - 容易循环依赖\n\n    - 不利于单元测试\n\n### 2\\. Setter 方法注入\n\n- 通过set方法注入\n\n- **适合可变依赖、非必须依赖**\n\n- Spring早期主流方式，现在极少用\n\n### 3\\. 构造器注入（Spring官方推荐）\n\n- 通过构造方法注入所有依赖\n\n- **优点**：\n        \n\n    - 保证Bean初始化完全、线程安全\n\n    - 避免循环依赖（提前暴露依赖）\n\n    - 适合必须依赖、不可缺依赖\n\n    - 方便单元测试\n\n### 4\\. 三种注入终极对比\n\n- **必须依赖、核心业务** → 构造器注入（首选）\n\n- **可选依赖、动态修改** → Setter注入\n\n- **简单业务、快速开发** → 字段注入（不规范但常用）\n\n### 5、三种注入底层坑点补充\n\n- **字段注入 @Autowired**：Spring底层通过 **ReflectionUtils** 暴力反射赋值，跳过构造器，极易产生循环依赖、隐藏依赖、单元测试无法new独立对象\n\n- **Setter注入**：适合热更新配置、动态修改依赖，不会触发循环依赖卡死，但依赖不保证非空\n\n- **构造器注入**：Spring4\\.3\\+ 单Bean可省略@Autowired，自动构造注入，**强制依赖非空、线程安全、杜绝循环依赖、利于单元测试**，阿里\u002FSpring官方双推荐\n\n---\n\n## 三、Spring 循环依赖 完整原理 \\+ 三级缓存解决方案\n\n### 1\\. 什么是循环依赖\n\n**A依赖B，B依赖A**，互相嵌套依赖，导致创建死锁\n\n### 2\\. 哪些场景能解决、哪些不能解决（必考）\n\n- **可以解决**：**单例Bean、字段\u002Fsetter注入**\n\n- **无法解决**：\n\n\n    - 多例Bean（不缓存）\n\n    - 构造器注入循环依赖（创建即依赖，无解）\n\n    - 原型作用域Bean\n\n### 3\\. 三级缓存核心结构（核心）\n\n```plain\nSpring三级缓存结构\n一级缓存 singletonObjects：完整初始化完成的单例Bean\n二级缓存 earlySingletonObjects：已实例化、未填充属性的早期Bean\n三级缓存 singletonFactories：Bean工厂对象（提前暴露引用\u002F代理入口）\n\n```\n\n### 4\\. 三级缓存完整执行流程（满分背诵）\n\n以 A、B 互相依赖为例：\n\n1. **A开始实例化**，创建空对象，放入三级缓存\n\n2. **A填充属性**，发现需要B，去创建B\n\n3. **B实例化完成**，填充属性需要A\n\n4. B先查一级缓存无、二级无、**三级拿到A的早期引用**\n\n5. **B完成初始化**，进入一级缓存\n\n6. **A继续完成属性填充、初始化**\n\n7. A从三级移除 → 二级过渡 → **进入一级缓存**\n\n### 5\\. 三级缓存各自作用（面试追问）\n\n- **一级缓存**：存放最终成熟Bean，对外提供服务\n\n- **二级缓存**：解决普通循环依赖，存储半成品Bean，避免重复创建\n\n- **三级缓存**：核心！**解决AOP代理循环依赖**，提前暴露Bean引用与代理工厂\n\n### 6\\. 为什么需要三级缓存，二级不行？\n\n**如果没有三级缓存：普通依赖可以解决，AOP代理循环依赖必炸**\n\n三级缓存存放的是 ObjectFactory，可在早期直接返回**代理对象**，保证依赖双方拿到的是同一个代理Bean，杜绝循环依赖冲突。\n\n### 7、循环依赖高频终极答疑（面试绝杀）\n\n- **为什么构造器注入无法解决循环依赖？**\n构造器执行在**实例化阶段**，对象还没创建完成，根本没有机会放入三级缓存，依赖互相卡死，无解。\n\n- **为什么多例Bean无法解决循环依赖？**\n多例Bean不进入三级缓存、不做任何缓存，每次都是新建对象，无法提前暴露引用，循环依赖直接报错。\n\n- **二级缓存能干什么？**\n二级缓存可以解决**普通无代理**的循环依赖，但是解决不了**AOP代理Bean**的循环依赖。\n\n- **三级缓存核心价值**：延迟生成代理，保证早期暴露的引用和最终容器Bean是**同一个对象\u002F同一个代理**。\n\n---\n\n## 四、Spring AOP 完整原理\n\n### 1\\. AOP 概念\n\n**面向切面编程**，在不修改原有业务代码的前提下，对方法进行增强、拦截、扩展。\n\n核心思想：**横向扩展、解耦通用日志、事务、权限、监控**\n\n### 2\\. AOP 核心术语\n\n- **切点 Pointcut**：拦截哪些方法\n\n- **通知 Advice**：拦截后做什么（前置、后置、异常、环绕）\n\n- **切面 Aspect**：切点\\+通知结合体\n\n- **连接点 JoinPoint**：可被拦截的所有方法\n\n- **织入 Weaving**：将切面逻辑植入目标方法的过程\n\n### 3\\. AOP 执行时机（Bean生命周期）\n\n**Bean初始化后置处理阶段生成代理对象**\n\n目标Bean创建完成后，Spring通过后置处理器`AbstractAutoProxyCreator` 判断是否需要代理，需要则**生成代理Bean放入容器**，容器中最终存在的是代理对象而非原对象。\n\n### 4\\. AOP 完整执行链路\n\n```plain\nAOP调用流程\n1. 容器获取代理Bean\n2. 进入代理拦截器\n3. 执行前置通知 @Before\n4. 执行目标方法\n5. 执行后置通知 @After\n6. 执行返回通知 @AfterReturning\n7. 出现异常执行 @AfterThrowing\n8. 环绕通知包裹全程\n```\n\n### 5、AOP 五大通知执行顺序（必考）\n\n**正常执行顺序**：环绕前置 → @Before → 目标方法 → @After → @AfterReturning → 环绕后置\n\n**异常执行顺序**：环绕前置 → @Before → 目标方法报错 → @After → @AfterThrowing（无AfterReturning）\n\n### 6、AOP 代理失效经典场景（高频坑点）\n\n- **同类内部调用**：A类a方法调用本类b切面方法，AOP失效（绕过代理对象，直接this调用原对象）\n\n- **final\u002Fstatic\u002Fprivate方法**：无法被CGLIB\u002FJDK代理，切面失效\n\n- **构造方法切面**：Bean还未创建完成，无法织入切面\n\n**解决方案**：手动从容器获取自身代理对象、使用AopContext\\.currentProxy\\(\\)\n\n---\n\n## 五、JDK动态代理 vs CGLIB 动态代理（面试必考区别）\n\n### 1\\. 两种代理底层原理\n\n#### JDK 动态代理\n\n- **基于接口代理**\n\n- 底层通过反射生成接口实现类\n\n- **必须实现接口**，无接口无法代理\n\n- 只能拦截接口方法\n\n#### CGLIB 动态代理\n\n- **基于子类继承代理**\n\n- ASM字节码技术，动态生成目标类子类\n\n- **无需接口**，普通类也能代理\n\n- 无法代理final类、final方法、private方法\n\n### 2\\. Spring AOP 代理选择规则（必背）\n\n- **目标有接口 → 默认JDK动态代理**\n\n- **目标无接口 → 自动CGLIB代理**\n\n- SpringBoot2\\.0\\+ **默认强制CGLIB**\n\n### 4、动态代理性能 \\& 实战细节补充\n\n- **JDK动态代理**：启动创建代理类慢，运行调用快；接口方法有限，更稳定\n\n- **CGLIB动态代理**：基于ASM字节码生成，创建速度快；支持普通类；因为是继承代理，final类\u002F方法完全无法拦截\n\n- **Spring选择策略本质**：优先兼容无接口类，所以Boot默认统一CGLIB，减少切换成本\n\n### 3\\. 终极区别总结\n\n|对比维度|JDK动态代理|CGLIB动态代理|\n|---|---|---|\n|依赖条件|必须有接口|无需接口，继承父类|\n|底层技术|反射机制|ASM字节码生成|\n|代理范围|仅接口方法|所有非final、非private方法|\n|性能|调用快、创建慢|创建快、调用略快|\n\n---\n\n## 六、Spring核心终极面试总结（直接背诵）\n\n- **IOC原理**：控制反转将对象创建与依赖管理交给容器，DI注入实现解耦，Bean经历解析、实例化、注入、初始化、服务、销毁完整生命周期。\n\n- **注入方式**：构造器注入官方推荐保证安全，setter适配可选依赖，字段注入简洁但易循环依赖。\n\n- **循环依赖**：单例字段\u002Fsetter依赖可通过三级缓存解决，三级缓存专门解决AOP代理循环依赖，构造器循环依赖无解。\n\n- **AOP原理**：基于动态代理，在Bean初始化后置阶段生成代理对象，实现方法无侵入增强，用于事务、日志、权限。\n\n- **代理区别**：JDK代理基于接口、反射实现；CGLIB基于子类继承、ASM字节码实现，SpringBoot统一默认CGLIB，适配所有普通类与接口类。\n\n- **高频坑点**：同类内部调用AOP失效、构造器注入无解循环依赖、三级缓存专为解决代理循环依赖、final方法无法被代理。\n\n- **执行顺序**：AOP正常执行与异常执行顺序固定，环绕通知优先级最高，异常后不执行返回通知。","markdown",5181,{"frontmatter":49,"meta":50,"nodes":165},{},{"title":36,"description":51,"toc":52},"本文全覆盖 Spring 底层五大核心考点：IOC容器原理、Bean生命周期、三种注入方式、三级缓存解决循环依赖、AOP底层原理、JDK\u002FCGLIB动态代理区别，无废话、全面试高频、逻辑闭环、可直接背诵手撕面试。",{"title":4,"searchDepth":53,"depth":53,"links":54},5,[55,72,91,116,138,162],{"id":56,"depth":42,"text":57,"children":58},"spring-ioc","一、Spring IOC 核心原理",[59,63,66,69],{"id":60,"depth":61,"text":62},"spring-ioc-_1-ioc",3,"1. IOC 概念（控制反转）",{"id":64,"depth":61,"text":65},"spring-ioc-_2-ioc","2. IOC 核心作用",{"id":67,"depth":61,"text":68},"spring-ioc-_3-ioc","3. IOC 容器核心执行流程（必背）",{"id":70,"depth":61,"text":71},"spring-ioc-_4-bean","4. Bean 完整生命周期（满分背诵）",{"id":73,"depth":42,"text":74,"children":75},"spring","二、Spring 三种依赖注入方式 & 区别",[76,79,82,85,88],{"id":77,"depth":61,"text":78},"spring-_1-autowired","1. 字段注入（@Autowired）",{"id":80,"depth":61,"text":81},"spring-_2-setter","2. Setter 方法注入",{"id":83,"depth":61,"text":84},"spring-_3-spring","3. 构造器注入（Spring官方推荐）",{"id":86,"depth":61,"text":87},"spring-_4","4. 三种注入终极对比",{"id":89,"depth":61,"text":90},"spring-_5","5、三种注入底层坑点补充",{"id":92,"depth":42,"text":93,"children":94},"spring-1","三、Spring 循环依赖 完整原理 + 三级缓存解决方案",[95,98,101,104,107,110,113],{"id":96,"depth":61,"text":97},"spring-_1","1. 什么是循环依赖",{"id":99,"depth":61,"text":100},"spring-_2","2. 哪些场景能解决、哪些不能解决（必考）",{"id":102,"depth":61,"text":103},"spring-_3","3. 三级缓存核心结构（核心）",{"id":105,"depth":61,"text":106},"spring-_4-1","4. 三级缓存完整执行流程（满分背诵）",{"id":108,"depth":61,"text":109},"spring-_5-1","5. 三级缓存各自作用（面试追问）",{"id":111,"depth":61,"text":112},"spring-_6","6. 为什么需要三级缓存，二级不行？",{"id":114,"depth":61,"text":115},"spring-_7","7、循环依赖高频终极答疑（面试绝杀）",{"id":117,"depth":42,"text":118,"children":119},"spring-aop","四、Spring AOP 完整原理",[120,123,126,129,132,135],{"id":121,"depth":61,"text":122},"spring-aop-_1-aop","1. AOP 概念",{"id":124,"depth":61,"text":125},"spring-aop-_2-aop","2. AOP 核心术语",{"id":127,"depth":61,"text":128},"spring-aop-_3-aop-bean","3. AOP 执行时机（Bean生命周期）",{"id":130,"depth":61,"text":131},"spring-aop-_4-aop","4. AOP 完整执行链路",{"id":133,"depth":61,"text":134},"spring-aop-_5aop","5、AOP 五大通知执行顺序（必考）",{"id":136,"depth":61,"text":137},"spring-aop-_6aop","6、AOP 代理失效经典场景（高频坑点）",{"id":139,"depth":42,"text":140,"children":141},"jdk-vs-cglib","五、JDK动态代理 vs CGLIB 动态代理（面试必考区别）",[142,153,156,159],{"id":143,"depth":61,"text":144,"children":145},"jdk-vs-cglib-_1","1. 两种代理底层原理",[146,150],{"id":147,"depth":148,"text":149},"jdk-vs-cglib-_1-jdk",4,"JDK 动态代理",{"id":151,"depth":148,"text":152},"jdk-vs-cglib-_1-cglib","CGLIB 动态代理",{"id":154,"depth":61,"text":155},"jdk-vs-cglib-_2-spring-aop","2. Spring AOP 代理选择规则（必背）",{"id":157,"depth":61,"text":158},"jdk-vs-cglib-_4","4、动态代理性能 & 实战细节补充",{"id":160,"depth":61,"text":161},"jdk-vs-cglib-_3","3. 终极区别总结",{"id":163,"depth":42,"text":164},"spring-2","六、Spring核心终极面试总结（直接背诵）",[166,170,179,182,185,191,201,207,209,225,227,230,275,277,282,291,294,296,298,327,329,342,344,370,372,392,394,422,424,426,428,434,436,464,466,471,473,476,519,521,545,547,552,559,561,603,605,607,609,615,621,623,655,657,662,673,675,680,682,688,694,696,716,722,724,726,728,731,750,752,771,773,791,793,813,815,880,882,884],[167,168,36],"h1",{"id":169},"spring-iocbeanaop",[171,172,173,174,178],"p",{},"本文全覆盖 Spring 底层五大核心考点：",[175,176,177],"strong",{},"IOC容器原理、Bean生命周期、三种注入方式、三级缓存解决循环依赖、AOP底层原理、JDK\u002FCGLIB动态代理区别","，无废话、全面试高频、逻辑闭环、可直接背诵手撕面试。",[180,181,57],"h2",{"id":56},[183,184,62],"h3",{"id":60},[171,186,187,190],{},[175,188,189],{},"传统开发","：开发者主动 new 对象、管理依赖、控制生命周期（程序员主动）",[171,192,193,196,197,200],{},[175,194,195],{},"IOC控制反转","：",[175,198,199],{},"将对象创建、依赖管理、生命周期控制权反转交给Spring容器","（容器主动）",[171,202,203,206],{},[175,204,205],{},"DI依赖注入","：IOC的实现手段，容器自动给Bean赋值、注入依赖",[183,208,65],{"id":64},[210,211,212,216,219,222],"ul",{},[213,214,215],"li",{},"解耦：彻底消除硬编码 new 对象",[213,217,218],{},"统一管理Bean生命周期",[213,220,221],{},"自动依赖注入、自动解决依赖关系",[213,223,224],{},"为AOP、事务、Spring全家桶提供底层支撑",[183,226,68],{"id":67},[171,228,229],{},"Spring 启动加载 Bean 完整流程：",[231,232,233,239,245,251,257,263,269],"ol",{},[213,234,235,238],{},[175,236,237],{},"资源加载、扫描配置","：加载xml\u002F注解配置、扫描包路径，得到Bean定义信息",[213,240,241,244],{},[175,242,243],{},"解析Bean定义（BeanDefinition）","：不创建对象，仅解析类信息、属性、作用域、依赖，存入BeanDefinitionMap",[213,246,247,250],{},[175,248,249],{},"Bean实例化","：单例Bean在容器启动阶段统一通过反射创建对象",[213,252,253,256],{},[175,254,255],{},"依赖注入DI","：自动填充属性、注入依赖Bean",[213,258,259,262],{},[175,260,261],{},"初始化前置后置","：Bean后置处理器、InitializingBean、init-method",[213,264,265,268],{},[175,266,267],{},"完成初始化","：放入单例池，对外提供服务",[213,270,271,274],{},[175,272,273],{},"容器关闭","：执行销毁方法",[183,276,71],{"id":70},[171,278,279],{},[175,280,281],{},"扫描解析 → 实例化 → 依赖注入 → 初始化 → 就绪使用 → 销毁",[283,284,286],"pre",{"language":285},"plain",[287,288,290],"code",{"class":289},"language-plain","Bean生命周期完整链路\n1. 解析配置生成 BeanDefinition\n2. 反射实例化对象（空对象）\n3. 依赖注入填充属性\n4. 执行BeanPostProcessor前置处理\n5. 执行InitializingBean \u002F init-method\n6. 执行BeanPostProcessor后置处理（AOP代理在此步生成）\n7. Bean就绪对外提供服务\n8. 容器关闭执行销毁方法\n",[292,293],"hr",{},[180,295,74],{"id":73},[183,297,78],{"id":77},[210,299,300,303,309],{},[213,301,302],{},"直接注解在字段上，简洁方便",[213,304,305,308],{},[175,306,307],{},"底层原理","：反射暴力赋值",[213,310,311,316],{},[171,312,313,196],{},[175,314,315],{},"弊端",[210,317,318,321,324],{},[213,319,320],{},"违反单一职责",[213,322,323],{},"容易循环依赖",[213,325,326],{},"不利于单元测试",[183,328,81],{"id":80},[210,330,331,334,339],{},[213,332,333],{},"通过set方法注入",[213,335,336],{},[175,337,338],{},"适合可变依赖、非必须依赖",[213,340,341],{},"Spring早期主流方式，现在极少用",[183,343,84],{"id":83},[210,345,346,349],{},[213,347,348],{},"通过构造方法注入所有依赖",[213,350,351,356],{},[171,352,353,196],{},[175,354,355],{},"优点",[210,357,358,361,364,367],{},[213,359,360],{},"保证Bean初始化完全、线程安全",[213,362,363],{},"避免循环依赖（提前暴露依赖）",[213,365,366],{},"适合必须依赖、不可缺依赖",[213,368,369],{},"方便单元测试",[183,371,87],{"id":86},[210,373,374,380,386],{},[213,375,376,379],{},[175,377,378],{},"必须依赖、核心业务"," → 构造器注入（首选）",[213,381,382,385],{},[175,383,384],{},"可选依赖、动态修改"," → Setter注入",[213,387,388,391],{},[175,389,390],{},"简单业务、快速开发"," → 字段注入（不规范但常用）",[183,393,90],{"id":89},[210,395,396,406,412],{},[213,397,398,401,402,405],{},[175,399,400],{},"字段注入 @Autowired","：Spring底层通过 ",[175,403,404],{},"ReflectionUtils"," 暴力反射赋值，跳过构造器，极易产生循环依赖、隐藏依赖、单元测试无法new独立对象",[213,407,408,411],{},[175,409,410],{},"Setter注入","：适合热更新配置、动态修改依赖，不会触发循环依赖卡死，但依赖不保证非空",[213,413,414,417,418,421],{},[175,415,416],{},"构造器注入","：Spring4.3+ 单Bean可省略@Autowired，自动构造注入，",[175,419,420],{},"强制依赖非空、线程安全、杜绝循环依赖、利于单元测试","，阿里\u002FSpring官方双推荐",[292,423],{},[180,425,93],{"id":92},[183,427,97],{"id":96},[171,429,430,433],{},[175,431,432],{},"A依赖B，B依赖A","，互相嵌套依赖，导致创建死锁",[183,435,100],{"id":99},[210,437,438,446],{},[213,439,440,196,443],{},[175,441,442],{},"可以解决",[175,444,445],{},"单例Bean、字段\u002Fsetter注入",[213,447,448,453],{},[171,449,450,196],{},[175,451,452],{},"无法解决",[210,454,455,458,461],{},[213,456,457],{},"多例Bean（不缓存）",[213,459,460],{},"构造器注入循环依赖（创建即依赖，无解）",[213,462,463],{},"原型作用域Bean",[183,465,103],{"id":102},[283,467,468],{"language":285},[287,469,470],{"class":289},"Spring三级缓存结构\n一级缓存 singletonObjects：完整初始化完成的单例Bean\n二级缓存 earlySingletonObjects：已实例化、未填充属性的早期Bean\n三级缓存 singletonFactories：Bean工厂对象（提前暴露引用\u002F代理入口）\n",[183,472,106],{"id":105},[171,474,475],{},"以 A、B 互相依赖为例：",[231,477,478,484,490,496,502,508,513],{},[213,479,480,483],{},[175,481,482],{},"A开始实例化","，创建空对象，放入三级缓存",[213,485,486,489],{},[175,487,488],{},"A填充属性","，发现需要B，去创建B",[213,491,492,495],{},[175,493,494],{},"B实例化完成","，填充属性需要A",[213,497,498,499],{},"B先查一级缓存无、二级无、",[175,500,501],{},"三级拿到A的早期引用",[213,503,504,507],{},[175,505,506],{},"B完成初始化","，进入一级缓存",[213,509,510],{},[175,511,512],{},"A继续完成属性填充、初始化",[213,514,515,516],{},"A从三级移除 → 二级过渡 → ",[175,517,518],{},"进入一级缓存",[183,520,109],{"id":108},[210,522,523,529,535],{},[213,524,525,528],{},[175,526,527],{},"一级缓存","：存放最终成熟Bean，对外提供服务",[213,530,531,534],{},[175,532,533],{},"二级缓存","：解决普通循环依赖，存储半成品Bean，避免重复创建",[213,536,537,540,541,544],{},[175,538,539],{},"三级缓存","：核心！",[175,542,543],{},"解决AOP代理循环依赖","，提前暴露Bean引用与代理工厂",[183,546,112],{"id":111},[171,548,549],{},[175,550,551],{},"如果没有三级缓存：普通依赖可以解决，AOP代理循环依赖必炸",[171,553,554,555,558],{},"三级缓存存放的是 ObjectFactory，可在早期直接返回",[175,556,557],{},"代理对象","，保证依赖双方拿到的是同一个代理Bean，杜绝循环依赖冲突。",[183,560,115],{"id":114},[210,562,563,573,579,593],{},[213,564,565,568,569,572],{},[175,566,567],{},"为什么构造器注入无法解决循环依赖？","\n构造器执行在",[175,570,571],{},"实例化阶段","，对象还没创建完成，根本没有机会放入三级缓存，依赖互相卡死，无解。",[213,574,575,578],{},[175,576,577],{},"为什么多例Bean无法解决循环依赖？","\n多例Bean不进入三级缓存、不做任何缓存，每次都是新建对象，无法提前暴露引用，循环依赖直接报错。",[213,580,581,584,585,588,589,592],{},[175,582,583],{},"二级缓存能干什么？","\n二级缓存可以解决",[175,586,587],{},"普通无代理","的循环依赖，但是解决不了",[175,590,591],{},"AOP代理Bean","的循环依赖。",[213,594,595,598,599,602],{},[175,596,597],{},"三级缓存核心价值","：延迟生成代理，保证早期暴露的引用和最终容器Bean是",[175,600,601],{},"同一个对象\u002F同一个代理","。",[292,604],{},[180,606,118],{"id":117},[183,608,122],{"id":121},[171,610,611,614],{},[175,612,613],{},"面向切面编程","，在不修改原有业务代码的前提下，对方法进行增强、拦截、扩展。",[171,616,617,618],{},"核心思想：",[175,619,620],{},"横向扩展、解耦通用日志、事务、权限、监控",[183,622,125],{"id":124},[210,624,625,631,637,643,649],{},[213,626,627,630],{},[175,628,629],{},"切点 Pointcut","：拦截哪些方法",[213,632,633,636],{},[175,634,635],{},"通知 Advice","：拦截后做什么（前置、后置、异常、环绕）",[213,638,639,642],{},[175,640,641],{},"切面 Aspect","：切点+通知结合体",[213,644,645,648],{},[175,646,647],{},"连接点 JoinPoint","：可被拦截的所有方法",[213,650,651,654],{},[175,652,653],{},"织入 Weaving","：将切面逻辑植入目标方法的过程",[183,656,128],{"id":127},[171,658,659],{},[175,660,661],{},"Bean初始化后置处理阶段生成代理对象",[171,663,664,665,668,669,672],{},"目标Bean创建完成后，Spring通过后置处理器",[287,666,667],{},"AbstractAutoProxyCreator"," 判断是否需要代理，需要则",[175,670,671],{},"生成代理Bean放入容器","，容器中最终存在的是代理对象而非原对象。",[183,674,131],{"id":130},[283,676,677],{"language":285},[287,678,679],{"class":289},"AOP调用流程\n1. 容器获取代理Bean\n2. 进入代理拦截器\n3. 执行前置通知 @Before\n4. 执行目标方法\n5. 执行后置通知 @After\n6. 执行返回通知 @AfterReturning\n7. 出现异常执行 @AfterThrowing\n8. 环绕通知包裹全程",[183,681,134],{"id":133},[171,683,684,687],{},[175,685,686],{},"正常执行顺序","：环绕前置 → @Before → 目标方法 → @After → @AfterReturning → 环绕后置",[171,689,690,693],{},[175,691,692],{},"异常执行顺序","：环绕前置 → @Before → 目标方法报错 → @After → @AfterThrowing（无AfterReturning）",[183,695,137],{"id":136},[210,697,698,704,710],{},[213,699,700,703],{},[175,701,702],{},"同类内部调用","：A类a方法调用本类b切面方法，AOP失效（绕过代理对象，直接this调用原对象）",[213,705,706,709],{},[175,707,708],{},"final\u002Fstatic\u002Fprivate方法","：无法被CGLIB\u002FJDK代理，切面失效",[213,711,712,715],{},[175,713,714],{},"构造方法切面","：Bean还未创建完成，无法织入切面",[171,717,718,721],{},[175,719,720],{},"解决方案","：手动从容器获取自身代理对象、使用AopContext.currentProxy()",[292,723],{},[180,725,140],{"id":139},[183,727,144],{"id":143},[729,730,149],"h4",{"id":147},[210,732,733,738,741,747],{},[213,734,735],{},[175,736,737],{},"基于接口代理",[213,739,740],{},"底层通过反射生成接口实现类",[213,742,743,746],{},[175,744,745],{},"必须实现接口","，无接口无法代理",[213,748,749],{},"只能拦截接口方法",[729,751,152],{"id":151},[210,753,754,759,762,768],{},[213,755,756],{},[175,757,758],{},"基于子类继承代理",[213,760,761],{},"ASM字节码技术，动态生成目标类子类",[213,763,764,767],{},[175,765,766],{},"无需接口","，普通类也能代理",[213,769,770],{},"无法代理final类、final方法、private方法",[183,772,155],{"id":154},[210,774,775,780,785],{},[213,776,777],{},[175,778,779],{},"目标有接口 → 默认JDK动态代理",[213,781,782],{},[175,783,784],{},"目标无接口 → 自动CGLIB代理",[213,786,787,788],{},"SpringBoot2.0+ ",[175,789,790],{},"默认强制CGLIB",[183,792,158],{"id":157},[210,794,795,801,807],{},[213,796,797,800],{},[175,798,799],{},"JDK动态代理","：启动创建代理类慢，运行调用快；接口方法有限，更稳定",[213,802,803,806],{},[175,804,805],{},"CGLIB动态代理","：基于ASM字节码生成，创建速度快；支持普通类；因为是继承代理，final类\u002F方法完全无法拦截",[213,808,809,812],{},[175,810,811],{},"Spring选择策略本质","：优先兼容无接口类，所以Boot默认统一CGLIB，减少切换成本",[183,814,161],{"id":160},[816,817,818,832],"table",{},[819,820,821],"thead",{},[822,823,824,828,830],"tr",{},[825,826,827],"th",{},"对比维度",[825,829,799],{},[825,831,805],{},[833,834,835,847,858,869],"tbody",{},[822,836,837,841,844],{},[838,839,840],"td",{},"依赖条件",[838,842,843],{},"必须有接口",[838,845,846],{},"无需接口，继承父类",[822,848,849,852,855],{},[838,850,851],{},"底层技术",[838,853,854],{},"反射机制",[838,856,857],{},"ASM字节码生成",[822,859,860,863,866],{},[838,861,862],{},"代理范围",[838,864,865],{},"仅接口方法",[838,867,868],{},"所有非final、非private方法",[822,870,871,874,877],{},[838,872,873],{},"性能",[838,875,876],{},"调用快、创建慢",[838,878,879],{},"创建快、调用略快",[292,881],{},[180,883,164],{"id":163},[210,885,886,892,898,904,910,916,922],{},[213,887,888,891],{},[175,889,890],{},"IOC原理","：控制反转将对象创建与依赖管理交给容器，DI注入实现解耦，Bean经历解析、实例化、注入、初始化、服务、销毁完整生命周期。",[213,893,894,897],{},[175,895,896],{},"注入方式","：构造器注入官方推荐保证安全，setter适配可选依赖，字段注入简洁但易循环依赖。",[213,899,900,903],{},[175,901,902],{},"循环依赖","：单例字段\u002Fsetter依赖可通过三级缓存解决，三级缓存专门解决AOP代理循环依赖，构造器循环依赖无解。",[213,905,906,909],{},[175,907,908],{},"AOP原理","：基于动态代理，在Bean初始化后置阶段生成代理对象，实现方法无侵入增强，用于事务、日志、权限。",[213,911,912,915],{},[175,913,914],{},"代理区别","：JDK代理基于接口、反射实现；CGLIB基于子类继承、ASM字节码实现，SpringBoot统一默认CGLIB，适配所有普通类与接口类。",[213,917,918,921],{},[175,919,920],{},"高频坑点","：同类内部调用AOP失效、构造器注入无解循环依赖、三级缓存专为解决代理循环依赖、final方法无法被代理。",[213,923,924,927],{},[175,925,926],{},"执行顺序","：AOP正常执行与异常执行顺序固定，环绕通知优先级最高，异常后不执行返回通知。"]