From dfc8c16529827d57601d3fb801882ae82c8bbcb7 Mon Sep 17 00:00:00 2001 From: vfdxvffd <2201986113@qq.com> Date: Thu, 15 Apr 2021 15:43:53 +0800 Subject: [PATCH] =?UTF-8?q?[=E6=9B=B4=E6=96=B0]=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E4=BA=86v0.5=EF=BC=88Pre-release=EF=BC=89=EF=BC=8C=E5=BC=95?= =?UTF-8?q?=E5=85=A5=E4=BA=8C=E5=B1=82=E4=BE=9D=E8=B5=96=EF=BC=88=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E4=BA=8Espring=EF=BC=89=E8=A7=A3=E5=86=B3=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E4=BE=9D=E8=B5=96=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 35 ++++++++++++---- ...64\346\226\260\346\227\245\345\277\227.md" | 41 ++++++++++++++++--- img/summerDoubleCache.svg | 1 + 3 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 img/summerDoubleCache.svg diff --git a/README.md b/README.md index 7cfd5a6..dec33ff 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Summer -[![](https://img.shields.io/badge/Release-v1.4-orange)](https://github.com/vfdxvffd/Summer/releases/tag/v1.4)    [![](https://img.shields.io/badge/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3-Summer-informational)](Summer使用文档.md)    [![](https://img.shields.io/badge/%E6%9B%B4%E6%96%B0%E6%97%A5%E5%BF%97-log-important)](Summer更新日志.md) +[![](https://img.shields.io/badge/Release-v0.5-orange)](https://github.com/vfdxvffd/Summer/releases/tag/v0.5)    [![](https://img.shields.io/badge/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3-Summer-informational)](Summer使用文档.md)    [![](https://img.shields.io/badge/%E6%9B%B4%E6%96%B0%E6%97%A5%E5%BF%97-log-important)](Summer更新日志.md) ​ 参考`Spring`框架实现一个简易类似的`Java`框架。计划陆续实现`IOC`、`AOP`、以及`数据访问模块和事务控制模块`。项目持续维护中...欢迎Star!Thanks~~~ @@ -18,11 +18,32 @@ JDK 8 ## 如何使用 -​ 下载最新的jar包[![](https://img.shields.io/badge/Release-v1.4-orange)](https://github.com/vfdxvffd/Summer/releases/tag/v1.4) ,将其导入项目中,即可使用,目录结构如下图,蓝色框内为`summer`的核心代码,`ch`包下为`logback`日志依赖,`net.sf.cglib`下为cglib动态代理的依赖,`org.slf4j`下为`slf4j`的日志门面依赖。 +​ 下载最新的jar包[![](https://img.shields.io/badge/Release-v0.5-orange)](https://github.com/vfdxvffd/Summer/releases/tag/v0.5) ,将其导入项目中,即可使用,目录结构如下图,蓝色框内为`summer`的核心代码,`ch`包下为`logback`日志依赖,`net.sf.cglib`下为cglib动态代理的依赖,`org.slf4j`下为`slf4j`的日志门面依赖。 ![](img/2021-04-11_00-45.png) -## Version 1.4 +## Version 0.5(Pre-release) + +
一次重大更新
+ +> bug描述:循环依赖的问题复现出来 + +​ 因为之前`v0.1`更新中引入的一个解决bug的方法导致了这个重大的bug,这次通过设置二级缓存来解决`循环依赖`的问题,具体bug的产生原因详情可见[更新日志](Summer更新日志.md),更新日志对这次bug的出现原因以及解决方法做了详细的说明。 + +**bug解决:** + +​ 针对目前掌握的代理方面的知识,对之前的做法做出一些调整。设置二级缓存,一级缓存一个(即真正的ioc容器),二级缓存两个,都是负责存放实例化但未初始化的对象,但一个是存放原对象,另一个负责存放代理对象,二级缓存的示意图如下: + +![](img/summerDoubleCache.svg) + +将ioc容器的构造过程分为四步来进行: + +1. 遍历包,找到所有需要被IOC管理的类,封装成`BeanDefinition` +2. 根据第一步获取到的`BeanDefinition`实例化那些单例且非延迟加载的对象,并将其加入到二级缓存的`earlyRealObjects`中 +3. 对第二步得到的`earlyRealObjects`中的对象进行检查,看是否需要设置代理,如果需要则对其进行代理,并将代理对象加入到二级缓存中的`earlyProxyObjects`中(并不删除`earlyRealObjects`中对应的真正的对象)。 +4. 对第二步得到的`earlyRealObjects`中的对象进行注入工作(即开始进行初始化),检查每个对象的每个域,如果标注了`@Autowired`注解且值为`null`,则对其进行注入工作,现在一级缓存中查找,如果有直接取出为其注入,如果没有检查二级缓存的`earlyProxyObjects`,如果有则取出为其注入,如果没有则接着检查二级缓存的`earlyRealObjects`,找到后为其注入,此时如果还没有则说明这个域对应的bean是非单例(prototype)模式或者懒加载模式的,则为其实例化并设置代理(如果需要),并初始化,然后注入其中。如果是非ioc容器管理的域,则直接注入`null`,也可以考虑改为抛出异常给用户提示。 + +## Version 0.4(Pre-release) 本次更新加入了新功能,修改了一个已知的bug @@ -34,7 +55,7 @@ JDK 8 > bug描述:对于一个没有任何域`且`需要代理的对象,进行注入工作的时候会由于没有域需要注入,从而直接判断其已经完成注入,而跳过了代理阶段。 -## Version 1.3 +## Version 0.3(Pre-release) - 本次更新引入了日志依赖,增加了对ioc构造过程中的日志记录 @@ -42,7 +63,7 @@ JDK 8 - 对于标注了`@Aspect`注解的类自动将其加入IOC容器中,不用再重复标注注解 -## Version 1.2 +## Version 0.2(Pre-release) 本次更新加入了一些新功能,修复了一些bug @@ -72,7 +93,7 @@ JDK 8 > bug描述:当一个待注入bean中有超过一个需要注入的域(带有注解@Autowired且未完成赋值),如果对它中的方法进行切面,这时切面方法会重复执行 -## Version 1.1 +## Version 0.1(Pre-release) ​ 本次更新主要修复了一些bug,以及优化了代码的结构 @@ -94,7 +115,7 @@ JDK 8 6. 抽取可重用方法。 -## Version 1.0 +## Version 0.0(Pre-release) 1. 完成IOC容器的初步搭建 diff --git "a/Summer\346\233\264\346\226\260\346\227\245\345\277\227.md" "b/Summer\346\233\264\346\226\260\346\227\245\345\277\227.md" index b6f60e5..3973d7c 100644 --- "a/Summer\346\233\264\346\226\260\346\227\245\345\277\227.md" +++ "b/Summer\346\233\264\346\226\260\346\227\245\345\277\227.md" @@ -1,6 +1,37 @@ # Summer更新日志 -## Version 1.4 +## Version 0.5(Pre-release) + +
一次重大更新
+ +> bug描述:循环依赖的问题复现出来 + +​ 在最早的版本`v0.0`中采用了`提前暴露对象`的方式解决了循环依赖的问题,其实就是先将所有的`单例且非延迟加载`的对象进行实例化而不进行初始化,存储在容器中,然后再对所有的单例非延迟加载对象进行注入初始化工作,从而解决循环依赖的问题。 + +​ 但是随着开始更新AOP的相关功能,由于需要为对象设置代理,以及本人技术认知的狭窄导致出现了一些bug到现在才发现。 + +​ 由于在`v0.1`版本中为了解决`bug1:修复对于注入对象的切面方法失效的bug`引用了`递归注入的方法`(具体可以翻看`v0.1`的更新日志,有详细介绍)。但这个方法又导致了原来的循环依赖的问题又重现出来(具体表现为A与B循环依赖,当给A注入B的值的时候发现B有未注入的A值,就又去给A注入,给A注入的时候又发现有B这个域没有注入,就又去注入B的值,如此循环往复导致又出现了循环依赖),而之前以为通过`提前暴露对象`的方式解决后就没有过多关注过循环依赖的问题导致这个bug一直没有被发现(还是自己的问题,没有反思为什么spring三级缓存才能解决的问题,自己居然用这么简单的思路去解决,这个问题很值得反思)。 + + + +​ 当时对代理对象的认知不太全面,私以为只要对对象设置了代理之后就无法更改其中的属性,但现在才明白:`只要修改被代理的原始类,那么代理类的行为会随着一起改变。`(也就是说假如原始类有一个`age`的属性,设置一个方法输出这个age,如果使用代理创建了对应的代理类后,原始类通过某些手段改变`age`的值,那么代理类输出的age也会随着改变。) + +​ 后面会抽时间出一篇总结`JDK动态代理`和`CGLib代理`的文章,将这段时间学到的东西做一个记录。 + +**bug解决:** + +​ 针对目前掌握的代理方面的知识,对之前的做法做出一些调整。设置二级缓存,一级缓存一个(即真正的ioc容器),二级缓存两个,都是负责存放实例化但未初始化的对象,但一个是存放原对象,另一个负责存放代理对象,二级缓存的示意图如下: + +![](img/summerDoubleCache.svg) + +将ioc容器的构造过程分为四步来进行: + +1. 遍历包,找到所有需要被IOC管理的类,封装成`BeanDefinition` +2. 根据第一步获取到的`BeanDefinition`实例化那些单例且非延迟加载的对象,并将其加入到二级缓存的`earlyRealObjects`中 +3. 对第二步得到的`earlyRealObjects`中的对象进行检查,看是否需要设置代理,如果需要则对其进行代理,并将代理对象加入到二级缓存中的`earlyProxyObjects`中(并不删除`earlyRealObjects`中对应的真正的对象)。 +4. 对第二步得到的`earlyRealObjects`中的对象进行注入工作(即开始进行初始化),检查每个对象的每个域,如果标注了`@Autowired`注解且值为`null`,则对其进行注入工作,现在一级缓存中查找,如果有直接取出为其注入,如果没有检查二级缓存的`earlyProxyObjects`,如果有则取出为其注入,如果没有则接着检查二级缓存的`earlyRealObjects`,找到后为其注入,此时如果还没有则说明这个域对应的bean是非单例(prototype)模式或者懒加载模式的,则为其实例化并设置代理(如果需要),并初始化,然后注入其中。如果是非ioc容器管理的域,则直接注入`null`,也可以考虑改为抛出异常给用户提示。 + +## Version 0.4(Pre-release) 本次更新加入了新功能,修改了一个已知的bug @@ -109,7 +140,7 @@ } ``` -## Version 1.3 +## Version 0.3(Pre-release) - 本次更新引入了日志依赖,增加了对ioc构造过程中的日志记录 @@ -117,7 +148,7 @@ - 对于标注了`@Aspect`注解的类自动将其加入IOC容器中,不用再重复标注注解 -## Version 1.2 +## Version 0.2(Pre-release) 本次更新加入了一些新功能,修复了一些bug @@ -178,7 +209,7 @@ ​ 修改时只需将设置代理的方法提出,每个class只需检查执行一次即可。 -## Version 1.1 +## Version 0.1(Pre-release) ​ 本次更新主要修复了一些bug,以及优化了代码的结构 @@ -273,7 +304,7 @@ 6. 抽取可重用方法。 -## Version 1.0 +## Version 0.0(Pre-release) 1. 完成IOC容器的初步搭建 diff --git a/img/summerDoubleCache.svg b/img/summerDoubleCache.svg new file mode 100644 index 0000000..84f29df --- /dev/null +++ b/img/summerDoubleCache.svg @@ -0,0 +1 @@ + 一级缓存中存放的都是已经创建完全的对象,即该对象已经实例化且初始化完成(但不保证该对象中域里的所有子域也注入完成)。当一个对象初始化完成后检查若需要代理就将earlyProxyObjects中的代理对象加入一级缓存,如果不需要就将earlyRealObjects中的原对象加入一级缓存中。加入一级缓存后同时需要删除在两个二级缓存中的对应内容 二级缓存的earlyRealObjects中存放的都是还未创建完成的半成品对象。即只完成了实例化但并未初始earlyRealObjectsobj4earlyProxyObjectsobj5obj6obj4Proxyobj6ProxyJDK动态代理CGLib代理二级缓存的earlyProxyObjects中存放的都是对earlyRealObjects中对象设置了代理后的代理对象,但也还没有进行初始化操作iocByNameobj1Proxyobj2obj3Proxy \ No newline at end of file