2022/09/27 周二 15:00:25.41

main
xuma 2 years ago
parent 709eee19c2
commit f1eb9969d2
  1. 10
      source/_posts/复习1.md
  2. 6
      source/_posts/复习2.md
  3. 96
      source/_posts/复习3.md
  4. 56
      source/_posts/复习4.md

@ -704,32 +704,32 @@ void transfer(Entry[] newTable, boolean rehash) {
* e 和 next 都是局部变量,用来指向当前节点和下一个节点
* 线程1(绿色)的临时变量 e 和 next 刚引用了这俩节点,还未来得及移动节点,发生了线程切换,由线程2(蓝色)完成扩容和迁移
![image-20210831084325075](img/image-20210831084325075.png)
![image-20210831084325075](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831084325075.png)
* 线程2 扩容完成,由于头插法,链表顺序颠倒。但线程1 的临时变量 e 和 next 还引用了这俩节点,还要再来一遍迁移
![image-20210831084723383](img/image-20210831084723383.png)
![image-20210831084723383](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831084723383.png)
* 第一次循环
* 循环接着线程切换前运行,注意此时 e 指向的是节点 a,next 指向的是节点 b
* e 头插 a 节点,注意图中画了两份 a 节点,但事实上只有一个(为了不让箭头特别乱画了两份)
* 当循环结束是 e 会指向 next 也就是 b 节点
![image-20210831084855348](img/image-20210831084855348.png)
![image-20210831084855348](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831084855348.png)
* 第二次循环
* next 指向了节点 a
* e 头插节点 b
* 当循环结束时,e 指向 next 也就是节点 a
![image-20210831085329449](img/image-20210831085329449.png)
![image-20210831085329449](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831085329449.png)
* 第三次循环
* next 指向了 null
* e 头插节点 a,**a 的 next 指向了 b**(之前 a.next 一直是 null),b 的 next 指向 a,死链已成
* 当循环结束时,e 指向 next 也就是 null,因此第四次循环时会正常退出
![image-20210831085543224](img/image-20210831085543224.png)
![image-20210831085543224](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831085543224.png)
**数据错乱(1.7,1.8 都会存在)**

@ -35,7 +35,7 @@ aside:
**六种状态及转换**
![image-20210831090722658](img/image-20210831090722658.png)
![image-20210831090722658](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831090722658.png)
分别是
@ -69,7 +69,7 @@ aside:
五种状态的说法来自于操作系统层面的划分
![image-20210831092652602](img/image-20210831092652602.png)
![image-20210831092652602](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831092652602.png)
* 运行态:分到 cpu 时间,能真正执行线程内代码的
* 就绪态:有资格分到 cpu 时间,但还未轮到它的
@ -100,7 +100,7 @@ aside:
3. 丢弃任务 java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
4. 丢弃最早排队任务 java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
![image-20210831093204388](img/image-20210831093204388.png)
![image-20210831093204388](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831093204388.png)
> ***代码说明***
>

@ -34,7 +34,7 @@ aside:
**结合一段 java 代码的执行理解内存划分**
![image-20210831165728217](img/image-20210831165728217.png)
![image-20210831165728217](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831165728217.png)
* 执行 javac 命令编译源代码为字节码
* 执行 java 命令
@ -70,7 +70,7 @@ aside:
* **永久代**是 Hotspot 虚拟机对 JVM 规范的实现(1.8 之前)
* **元空间**是 Hotspot 虚拟机对 JVM 规范的另一种实现(1.8 以后),使用本地内存作为这些信息的存储空间
![image-20210831170457337](img/image-20210831170457337.png)
![image-20210831170457337](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831170457337.png)
从这张图学到三点
@ -78,7 +78,7 @@ aside:
* X,Y 的类元信息是存储于元空间中,无法直接访问
* 可以用 X.class,Y.class 间接访问类元信息,它们俩属于 java 对象,我们的代码中可以使用
![image-20210831170512418](img/image-20210831170512418.png)
![image-20210831170512418](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831170512418.png)
从这张图可以学到
@ -95,7 +95,7 @@ aside:
**堆内存,按大小设置**
![image-20210831173130717](img/image-20210831173130717.png)
![image-20210831173130717](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831173130717.png)
解释:
@ -110,7 +110,7 @@ aside:
**堆内存,按比例设置**
![image-20210831173045700](img/image-20210831173045700.png)
![image-20210831173045700](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831173045700.png)
解释:
@ -121,7 +121,7 @@ aside:
**元空间内存设置**
![image-20210831173118634](img/image-20210831173118634.png)
![image-20210831173118634](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831173118634.png)
解释:
@ -137,7 +137,7 @@ aside:
**代码缓存内存设置**
![image-20210831173148816](img/image-20210831173148816.png)
![image-20210831173148816](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831173148816.png)
解释:
@ -151,7 +151,7 @@ aside:
**线程内存设置**
![image-20210831173155481](img/image-20210831173155481.png)
![image-20210831173155481](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831173155481.png)
> ***官方参考文档***
>
@ -172,7 +172,7 @@ aside:
标记清除法
![image-20210831211008162](img/image-20210831211008162.png)
![image-20210831211008162](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831211008162.png)
解释:
@ -190,7 +190,7 @@ aside:
标记整理法
![image-20210831211641241](img/image-20210831211641241.png)
![image-20210831211641241](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831211641241.png)
解释:
@ -208,7 +208,7 @@ aside:
标记复制法
![image-20210831212125813](img/image-20210831212125813.png)
![image-20210831212125813](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831212125813.png)
解释:
@ -244,39 +244,39 @@ GC 要点:
1. 伊甸园 eden,最初对象都分配到这里,与幸存区 survivor(分成 from 和 to)合称新生代,
![image-20210831213622704](img/image-20210831213622704.png)
![image-20210831213622704](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213622704.png)
2. 当伊甸园内存不足,标记伊甸园与 from(现阶段没有)的存活对象
![image-20210831213640110](img/image-20210831213640110.png)
![image-20210831213640110](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213640110.png)
3. 将存活对象采用复制算法复制到 to 中,复制完毕后,伊甸园和 from 内存都得到释放
![image-20210831213657861](img/image-20210831213657861.png)
![image-20210831213657861](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213657861.png)
4. 将 from 和 to 交换位置
![image-20210831213708776](img/image-20210831213708776.png)
![image-20210831213708776](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213708776.png)
5. 经过一段时间后伊甸园的内存又出现不足
![image-20210831213724858](img/image-20210831213724858.png)
![image-20210831213724858](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213724858.png)
6. 标记伊甸园与 from(现阶段没有)的存活对象
![image-20210831213737669](img/image-20210831213737669.png)
![image-20210831213737669](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213737669.png)
7. 将存活对象采用复制算法复制到 to 中
![image-20210831213804315](img/image-20210831213804315.png)
![image-20210831213804315](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213804315.png)
8. 复制完毕后,伊甸园和 from 内存都得到释放
![image-20210831213815371](img/image-20210831213815371.png)
![image-20210831213815371](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213815371.png)
9. 将 from 和 to 交换位置
![image-20210831213826017](img/image-20210831213826017.png)
![image-20210831213826017](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831213826017.png)
10. 老年代 old,当幸存区对象熬过几次回收(最多15次),晋升到老年代(幸存区内存不足或大对象会导致提前晋升)
@ -304,23 +304,23 @@ GC 要点:
1. 起始的三个对象还未处理完成,用灰色表示
<img src="img/image-20210831215016566.png" alt="image-20210831215016566" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831215016566.png" alt="image-20210831215016566" style="zoom:50%;" />
2. 该对象的引用已经处理完成,用黑色表示,黑色引用的对象变为灰色
<img src="img/image-20210831215033510.png" alt="image-20210831215033510" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831215033510.png" alt="image-20210831215033510" style="zoom:50%;" />
3. 依次类推
<img src="img/image-20210831215105280.png" alt="image-20210831215105280" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831215105280.png" alt="image-20210831215105280" style="zoom:50%;" />
4. 沿着引用链都标记了一遍
<img src="img/image-20210831215146276.png" alt="image-20210831215146276" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831215146276.png" alt="image-20210831215146276" style="zoom:50%;" />
5. 最后为标记的白色对象,即为垃圾
<img src="img/image-20210831215158311.png" alt="image-20210831215158311" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831215158311.png" alt="image-20210831215158311" style="zoom:50%;" />
**并发漏标问题**
@ -328,19 +328,19 @@ GC 要点:
1. 如图所示标记工作尚未完成
<img src="img/image-20210831215846876.png" alt="image-20210831215846876" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831215846876.png" alt="image-20210831215846876" style="zoom:50%;" />
2. 用户线程同时在工作,断开了第一层 3、4 两个对象之间的引用,这时对于正在处理 3 号对象的垃圾回收线程来讲,它会将 4 号对象当做是白色垃圾
<img src="img/image-20210831215904073.png" alt="image-20210831215904073" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831215904073.png" alt="image-20210831215904073" style="zoom:50%;" />
3. 但如果其他用户线程又建立了 2、4 两个对象的引用,这时因为 2 号对象是黑色已处理对象了,因此垃圾回收线程不会察觉到这个引用关系的变化,从而产生了漏标
<img src="img/image-20210831215919493.png" alt="image-20210831215919493" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831215919493.png" alt="image-20210831215919493" style="zoom:50%;" />
4. 如果用户线程让黑色对象引用了一个新增对象,一样会存在漏标问题
<img src="img/image-20210831220004062.png" alt="image-20210831220004062" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831220004062.png" alt="image-20210831220004062" style="zoom:50%;" />
因此对于**并发标记**而言,必须解决漏标问题,也就是要记录标记过程中的变化。有两种解决方法:
@ -383,53 +383,53 @@ GC 要点:
1. 初始时,所有区域都处于空闲状态
<img src="img/image-20210831222639754.png" alt="image-20210831222639754" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222639754.png" alt="image-20210831222639754" style="zoom:50%;" />
2. 创建了一些对象,挑出一些空闲区域作为伊甸园区存储这些对象
<img src="img/image-20210831222653802.png" alt="image-20210831222653802" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222653802.png" alt="image-20210831222653802" style="zoom:50%;" />
3. 当伊甸园需要垃圾回收时,挑出一个空闲区域作为幸存区,用复制算法复制存活对象,需要暂停用户线程
<img src="img/image-20210831222705814.png" alt="image-20210831222705814" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222705814.png" alt="image-20210831222705814" style="zoom:50%;" />
4. 复制完成,将之前的伊甸园内存释放
<img src="img/image-20210831222724999.png" alt="image-20210831222724999" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222724999.png" alt="image-20210831222724999" style="zoom:50%;" />
5. 随着时间流逝,伊甸园的内存又有不足
<img src="img/image-20210831222737928.png" alt="image-20210831222737928" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222737928.png" alt="image-20210831222737928" style="zoom:50%;" />
6. 将伊甸园以及之前幸存区中的存活对象,采用复制算法,复制到新的幸存区,其中较老对象晋升至老年代
<img src="img/image-20210831222752787.png" alt="image-20210831222752787" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222752787.png" alt="image-20210831222752787" style="zoom:50%;" />
7. 释放伊甸园以及之前幸存区的内存
<img src="img/image-20210831222803281.png" alt="image-20210831222803281" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222803281.png" alt="image-20210831222803281" style="zoom:50%;" />
**G1 回收阶段 - 并发标记与混合收集**
1. 当老年代占用内存超过阈值后,触发并发标记,这时无需暂停用户线程
<img src="img/image-20210831222813959.png" alt="image-20210831222813959" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222813959.png" alt="image-20210831222813959" style="zoom:50%;" />
2. 并发标记之后,会有重新标记阶段解决漏标问题,此时需要暂停用户线程。这些都完成后就知道了老年代有哪些存活对象,随后进入混合收集阶段。此时不会对所有老年代区域进行回收,而是根据**暂停时间目标**优先回收价值高(存活对象少)的区域(这也是 Gabage First 名称的由来)。
<img src="img/image-20210831222828104.png" alt="image-20210831222828104" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222828104.png" alt="image-20210831222828104" style="zoom:50%;" />
3. 混合收集阶段中,参与复制的有 eden、survivor、old,下图显示了伊甸园和幸存区的存活对象复制
<img src="img/image-20210831222841096.png" alt="image-20210831222841096" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222841096.png" alt="image-20210831222841096" style="zoom:50%;" />
4. 下图显示了老年代和幸存区晋升的存活对象的复制
<img src="img/image-20210831222859760.png" alt="image-20210831222859760" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222859760.png" alt="image-20210831222859760" style="zoom:50%;" />
5. 复制完成,内存得到释放。进入下一轮的新生代回收、并发标记、混合收集
<img src="img/image-20210831222919182.png" alt="image-20210831222919182" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210831222919182.png" alt="image-20210831222919182" style="zoom:50%;" />
## 4. 内存溢出
@ -529,7 +529,7 @@ GC 要点:
下面面试题的回答是错误的
![image-20210901110910016](img/image-20210901110910016.png)
![image-20210901110910016](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210901110910016.png)
错在哪了?
@ -563,7 +563,7 @@ GC 要点:
2. 通过 GC Root 的引用链,如果强引用不到该对象,该对象才能被回收
<img src="img/image-20210901111903574.png" alt="image-20210901111903574" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210901111903574.png" alt="image-20210901111903574" style="zoom:80%;" />
**软引用(SoftReference)**
@ -575,7 +575,7 @@ GC 要点:
4. 典型例子是反射数据
<img src="img/image-20210901111957328.png" alt="image-20210901111957328" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210901111957328.png" alt="image-20210901111957328" style="zoom:80%;" />
@ -589,7 +589,7 @@ GC 要点:
4. 典型例子是 ThreadLocalMap 中的 Entry 对象
<img src="img/image-20210901112107707.png" alt="image-20210901112107707" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210901112107707.png" alt="image-20210901112107707" style="zoom:80%;" />
@ -601,7 +601,7 @@ GC 要点:
3. 典型例子是 Cleaner 释放 DirectByteBuffer 关联的直接内存
<img src="img/image-20210901112157901.png" alt="image-20210901112157901" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210901112157901.png" alt="image-20210901112157901" style="zoom:80%;" />
@ -634,13 +634,13 @@ GC 要点:
1. 对 finalize 方法进行处理的核心逻辑位于 java.lang.ref.Finalizer 类中,它包含了名为 unfinalized 的静态变量(双向链表结构),Finalizer 也可被视为另一种引用对象(地位与软、弱、虚相当,只是不对外,无法直接使用)
2. 当重写了 finalize 方法的对象,在构造方法调用之时,JVM 都会将其包装成一个 Finalizer 对象,并加入 unfinalized 链表中
![image-20210901121032813](img/image-20210901121032813.png)
![image-20210901121032813](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210901121032813.png)
3. Finalizer 类中还有另一个重要的静态变量,即 ReferenceQueue 引用队列,刚开始它是空的。当狗对象可以被当作垃圾回收时,就会把这些狗对象对应的 Finalizer 对象加入此引用队列
4. 但此时 Dog 对象还没法被立刻回收,因为 unfinalized -> Finalizer 这一引用链还在引用它嘛,为的是【先别着急回收啊,等我调完 finalize 方法,再回收】
5. FinalizerThread 线程会从 ReferenceQueue 中逐一取出每个 Finalizer 对象,把它们从链表断开并真正调用 finallize 方法
![image-20210901122228916](img/image-20210901122228916.png)
![image-20210901122228916](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210901122228916.png)
6. 由于整个 Finalizer 对象已经从 unfinalized 链表中断开,这样没谁能引用到它和狗对象,所以下次 gc 时就被回收了

@ -81,7 +81,7 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* systemEnvironment - 保存系统环境键值
* 自定义 PropertySource - 保存自定义键值,例如来自于 *.properties 文件的键值
![image-20210902181639048](img/image-20210902181639048.png)
![image-20210902181639048](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902181639048.png)
**2. obtainFreshBeanFactory**
@ -91,7 +91,7 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* BeanDefinition 的来源有多种多样,可以是通过 xml 获得、配置类获得、组件扫描获得,也可以是编程添加
* 所有的 BeanDefinition 会存入 BeanFactory 中的 beanDefinitionMap 集合
![image-20210902182004819](img/image-20210902182004819.png)
![image-20210902182004819](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902182004819.png)
**3. prepareBeanFactory**
@ -105,7 +105,7 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* ApplicationContextAwareProcessor 用来解析 Aware 接口
* ApplicationListenerDetector 用来识别容器中 ApplicationListener 类型的 bean
![image-20210902182541925](img/image-20210902182541925.png)
![image-20210902182541925](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902182541925.png)
**4. postProcessBeanFactory**
@ -122,7 +122,7 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* PropertySourcesPlaceHolderConfigurer – 替换 BeanDefinition 中的 ${ }
* MapperScannerConfigurer – 补充 Mapper 接口对应的 BeanDefinition
![image-20210902183232114](img/image-20210902183232114.png)
![image-20210902183232114](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902183232114.png)
**6. registerBeanPostProcessors**
@ -132,14 +132,14 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* CommonAnnotationBeanPostProcessor 功能有:解析 @Resource,@PostConstruct,@PreDestroy
* AnnotationAwareAspectJAutoProxyCreator 功能有:为符合切点的目标 bean 自动创建代理
![image-20210902183520307](img/image-20210902183520307.png)
![image-20210902183520307](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902183520307.png)
**7. initMessageSource**
* 这一步是为 ApplicationContext 添加 messageSource 成员,实现国际化功能
* 去 beanFactory 内找名为 messageSource 的 bean,如果没有,则提供空的 MessageSource 实现
![image-20210902183819984](img/image-20210902183819984.png)
![image-20210902183819984](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902183819984.png)
**8. initApplicationContextEventMulticaster**
@ -148,7 +148,7 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* 去 beanFactory 找名为 applicationEventMulticaster 的 bean 作为事件广播器,若没有,会创建默认的事件广播器
* 之后就可以调用 ApplicationContext.publishEvent(事件对象) 来发布事件
![image-20210902183943469](img/image-20210902183943469.png)
![image-20210902183943469](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902183943469.png)
**9. onRefresh**
@ -165,7 +165,7 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* 来自于 @EventListener 的解析
* 要实现事件监听器,只需要实现 ApplicationListener 接口,重写其中 onApplicationEvent(E e) 方法即可
![image-20210902184343872](img/image-20210902184343872.png)
![image-20210902184343872](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902184343872.png)
**11. finishBeanFactoryInitialization**
@ -175,7 +175,7 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* singletonObjects 即单例池,缓存所有单例对象
* 对象的创建都分三个阶段,每一阶段都有不同的 bean 后处理器参与进来,扩展功能
![image-20210902184641623](img/image-20210902184641623.png)
![image-20210902184641623](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902184641623.png)
**12. finishRefresh**
@ -186,7 +186,7 @@ refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 Appl
* 调用 context 的 stop,即可触发所有实现 LifeCycle 接口 bean 的 stop
* 发布 ContextRefreshed 事件,整个 refresh 执行完成
![image-20210902185052433](img/image-20210902185052433.png)
![image-20210902185052433](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210902185052433.png)
@ -316,7 +316,7 @@ bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean
* 首先要明白,bean 的创建要遵循一定的步骤,必须是创建、注入、初始化三步,这些顺序不能乱
<img src="img/image-20210903085238916.png" alt="image-20210903085238916" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903085238916.png" alt="image-20210903085238916" style="zoom:50%;" />
* set 方法(包括成员变量)的循环依赖如图所示
@ -325,11 +325,11 @@ bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean
* a 的顺序,及 b 的顺序都能得到保障
<img src="img/image-20210903085454603.png" alt="image-20210903085454603" style="zoom: 33%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903085454603.png" alt="image-20210903085454603" style="zoom: 33%;" />
* 构造方法的循环依赖如图所示,显然无法用前面的方法解决
<img src="img/image-20210903085906315.png" alt="image-20210903085906315" style="zoom: 50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903085906315.png" alt="image-20210903085906315" style="zoom: 50%;" />
**构造循环依赖的解决**
@ -337,13 +337,13 @@ bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean
* a 注入 b 的代理对象,这样能够保证 a 的流程走通
* 后续需要用到 b 的真实对象时,可以通过代理间接访问
<img src="img/image-20210903091627659.png" alt="image-20210903091627659" style="zoom: 50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903091627659.png" alt="image-20210903091627659" style="zoom: 50%;" />
* 思路2
* a 注入 b 的工厂对象,让 b 的实例创建被推迟,这样能够保证 a 的流程先走通
* 后续需要用到 b 的真实对象时,再通过 ObjectFactory 工厂间接访问
<img src="img/image-20210903091743366.png" alt="image-20210903091743366" style="zoom:50%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903091743366.png" alt="image-20210903091743366" style="zoom:50%;" />
* 示例1:用 @Lazy 为构造方法参数生成代理
@ -561,7 +561,7 @@ public class App60_4 {
**一级缓存**
<img src="img/image-20210903100752165.png" alt="image-20210903100752165" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903100752165.png" alt="image-20210903100752165" style="zoom:80%;" />
作用是保证单例对象仅被创建一次
@ -570,7 +570,7 @@ public class App60_4 {
**一级缓存与循环依赖**
<img src="img/image-20210903100914140.png" alt="image-20210903100914140" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903100914140.png" alt="image-20210903100914140" style="zoom:80%;" />
一级缓存无法解决循环依赖问题,分析如下
@ -581,7 +581,7 @@ public class App60_4 {
**二级缓存**
<img src="img/image-20210903101849924.png" alt="image-20210903101849924" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903101849924.png" alt="image-20210903101849924" style="zoom:80%;" />
解决思路如下:
@ -599,7 +599,7 @@ public class App60_4 {
**二级缓存与创建代理**
<img src="img/image-20210903103030877.png" alt="image-20210903103030877" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903103030877.png" alt="image-20210903103030877" style="zoom:80%;" />
二级缓存无法正确处理循环依赖并且包含有代理创建的场景,分析如下
@ -609,7 +609,7 @@ public class App60_4 {
**三级缓存**
![image-20210903103628639](img/image-20210903103628639.png)
![image-20210903103628639](https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903103628639.png)
简单分析的话,只需要将代理的创建时机放在依赖注入之前即可,但 spring 仍然希望代理的创建时机在 init 之后,只有出现循环依赖时,才会将代理的创建时机提前。所以解决思路稍显复杂:
@ -1024,7 +1024,7 @@ public class Service7 {
4. 容器初始化后,会将上一步初始化好的重要组件,赋值给 DispatcherServlet 的成员变量,留待后用
<img src="img/image-20210903140657163.png" alt="image-20210903140657163" style="zoom: 80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903140657163.png" alt="image-20210903140657163" style="zoom: 80%;" />
**匹配阶段**
@ -1038,21 +1038,21 @@ public class Service7 {
③ 其中路径与处理器的映射关系在 HandlerMapping 初始化时就会建立好
<img src="img/image-20210903141017502.png" alt="image-20210903141017502" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903141017502.png" alt="image-20210903141017502" style="zoom:80%;" />
3. 将 HandlerMethod 连同匹配到的拦截器,生成调用链对象 HandlerExecutionChain 返回
<img src="img/image-20210903141124911.png" alt="image-20210903141124911" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903141124911.png" alt="image-20210903141124911" style="zoom:80%;" />
4. 遍历HandlerAdapter 处理器适配器,找到能处理 HandlerMethod 的适配器对象,开始调用
<img src="img/image-20210903141204799.png" alt="image-20210903141204799" style="zoom:80%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903141204799.png" alt="image-20210903141204799" style="zoom:80%;" />
**调用阶段**
1. 执行拦截器 preHandle
<img src="img/image-20210903141445870.png" alt="image-20210903141445870" style="zoom: 67%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903141445870.png" alt="image-20210903141445870" style="zoom: 67%;" />
2. 由 HandlerAdapter 调用 HandlerMethod
@ -1060,7 +1060,7 @@ public class Service7 {
② 调用后处理不同类型的返回值
<img src="img/image-20210903141658199.png" alt="image-20210903141658199" style="zoom:67%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903141658199.png" alt="image-20210903141658199" style="zoom:67%;" />
3. 第 2 步没有异常
@ -1070,11 +1070,11 @@ public class Service7 {
③ 解析视图,得到 View 对象,进行视图渲染
<img src="img/image-20210903141749830.png" alt="image-20210903141749830" style="zoom:67%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903141749830.png" alt="image-20210903141749830" style="zoom:67%;" />
4. 第 2 步有异常,进入 HandlerExceptionResolver 异常处理流程
<img src="img/image-20210903141844185.png" alt="image-20210903141844185" style="zoom:67%;" />
<img src="https://imgs-1302910354.cos.ap-shanghai.myqcloud.com/images/image-20210903141844185.png" alt="image-20210903141844185" style="zoom:67%;" />
5. 最后都会执行拦截器的 afterCompletion 方法

Loading…
Cancel
Save