Spring Bean容器初始化
1. 第一版
beanDefinition 容器定义类 持有 object(普通对象)
beanFactory 工厂 持有 currnetHashMap 存储 beanDefinition:
put 模拟注册
get 模拟获取使用
2. 第二版
bean对象 -> bean类信息
容器初始化时候再实例化bean对象
对外来的考虑:活动频发、流量爆增、需求迭代。
单例获取->缓存
3. 第三版
bean的创建方式,有两种:
一个是Java自带的DeclaredConstructor。
一个是cglib动态自动创建的。
采用策略设计模式进行。
Java反射创建对象。
4. 第四版
类的属性填充。
for循环+递归 -> 引用型对象循环依赖问题。
5. 第五版
资源加载器。
xml资源处理器。
将配置信息注册到Spring容器中去。
6. 第六版
postProcessor、beforeProcessor
业务的拆分与隔离。
逻辑做到分层、分区、分块。代码逻辑有步骤感。
7. 第七版
A继承B实现C时,C的接口方法由A继承的父类B实现,这样的操作都蛮有意思的。也是可以复用到通常的业务系统开发中进行处理一些复杂逻辑的功能分层,做到程序的可扩展、易维护等特性。
Bean的初始化和销毁。
8. 第八版
定义接口Aware,在Spring框架中它是一种感知标记性接口,具体的子类定义和实现能感知容器中的相关对象。也就是通过这个桥梁,向具体的实现类中提供容器服务。
9. 第九版
Bean对象->属性信息->对象创建->属性填充->初始操作->注册销毁->单例判断。
factory.isSingleton(),用于决定是否使用内存存放对象信息。
FactoryBeanRegistrySupport 类主要处理的就是关于 FactoryBean 此类对象的注册 操作,之所以放到这样一个单独的类里,就是希望做到不同领域模块下只负责各自 需要完成的功能,避免因为扩展导致类膨胀到难以维护。
代理类。
在Spring框架整个开发的过程中,前期的各个功能接口类扩展的像膨胀了似的,但到后期在完善功能时,就没有那么难了,反而深入理解后会觉得功能的补充,都比较简单。只需要再所遇领域范围内进行扩展相应的服务实现即可。
10. 第十版
设计和实现 Spring Event 的容 器事件和事件监听器功能,最终可以让我们在现有实现的 Spring 框架中可以 定义、监听和发布自己的事件信息。
11. 第十一版
发布订阅模式
ApplicationContextEvent 是定义事件的抽象类,所有的事件包括关闭、刷新,以及 用户自己实现的事件,都需要继承这个类。
ContextClosedEvent、ContextRefreshedEvent,分别是 Spring 框架自己实现的两 个事件类,可以用于监听刷新和关闭动作。
事件发布者、注册事件监听器、发布容器刷新完成事件,三个方法用于处
理事件操作。
初始化事件发布者(initApplicationEventMulticaster),主要用于实例化一个
SimpleApplicationEventMulticaster,这是一个事件广播器。
注册事件监听器(registerListeners),通过 getBeansOfType 方法获取到所有从
spring.xml 中加载到的事件配置 Bean 对象。
发布容器刷新完成事件(finishRefresh),发布了第一个服务器启动完成后的事件,这
个事件通过 publishEvent 发布出去,其实也就是调用了
applicationEventMulticaster.multicastEvent(event); 方法。
最后是一个 close 方法中,新增加了发布一个容器关闭事件。
publishEvent(new ContextClosedEvent(this));
12. 第十二版
基于JDK、CGlib实现AOP切面。
成体系学习,加强技术栈知识的完整性,才能更好的用上这些学习到的编码能力。
拦截器、类拦截、方法拦截、代理类、反射执行。
13. 第十三版
职责划分很重要。
在 XmlBeanDefinitionReader 中解析<context:component-scan />标签,扫描类 组装 BeanDefinition 然后注册到容器中的操作在 ClassPathBeanDefinitionScanner#doScan 中实现。
14. IOC
在 Spring 框架中,Advice都是通过方法拦截器MethodInterceptor实现的。环绕Advice类似一个拦截器的链路。
15. Bean 的生命周期
通过对 Bean 生命周期的调整,在创建 AOP 代理对象就可 以把代理对象的属性信息填充进去了。
还有一块是关于在 TargetSource#getTargetClass 中关于是否为 CGlib 的 方法判断,只有这样操作才可以获取到争取的类信息。
Bean 的生命周期,在创建类的操作中完成代 理对象的创建,通过这样的方式就可以让代理对象中的属性也可以随着创建过程被 填充进去。
16. 三级缓存处理循环依赖
自身依赖于自身、互相循环依赖、多组循环依赖。
三个缓存分别存放了成品对象、半成品对象(未填充属性值)、代理对象,分阶段存放对象内容,来解决循环依赖问题。
如只有一级缓存处理流程没法拆分,复杂度也会增加,同时半成品对象可能会有空指针异常。而将半成品与成品对象分开,处理起来也更加优雅、简单、易扩展。
另外Spring的两大特性中不仅有IOC还有AOP,也就是基于字节码增强后的方法,该存放到哪,而三级缓存最主要,要解决的循环依赖就是对AOP 的处理,但如果把AOP代理对象的创建提前,那么二级缓存也一样可以解决。但是,这就违背了 Spring 创建对象的原则,Spring 更 喜欢把所有的普通 Bean 都初始化完成,在处理代理对象的初始化。
在解决循环依赖的核心流程中,主要是提前暴露对象的设计,以及建立三级缓存的 数据结构来存放不同时期的对象,如果说没有如切面和工厂中的代理对象,那么二 级缓存也就可以解决了,哪怕是只有一级缓存。但为了设计上的合理和可扩展性, 所以创建了三级缓存来放置不同时期的对象。
Spring 中所有的功能都是以解决 Java 编程中的特性而存在的,就像我们本章节处 理的循环依赖,如果没有 Spring 框架的情况下,可能我们也会尽可能避免写出循 环依赖的操作,因为在没有经过加工处理后,这样的依赖关系肯定会报错的。那么 这也就是程序从能用到好用的升级。
17. 数据类型转换
如果你也是这样的工程师,其实在你不去刻意追求大厂、高薪、好职位的时 候,也会把你送到那个位置上去。想不被这个已经有些内卷的行业打下去,那 么基本就需要选择一条能沉淀下来核心知识的路径来提升自己,做好长期规 划,让以后你的 30 岁有 30 岁的能力,35 岁有 35 岁的经历!
类的层次结构的划分
接口、抽象类、实现具体类。
中间利于扩展。
前置、后置、中间扩展逻辑。
接口定义、类实现接口、抽象类实现接口、继承类、继承抽象类,很好的隔离类的基础功能、通用功能和业务功能。
考虑职责划分、共性分离。
标记作用的接口
具体的功能由继承此接口的其他功能性接口定义具体方法,最终这个接口就可以通过 instanceof 进行判断和调用。
有了标记的存在更方便类的操作和具体判断实现。
在 Spring 中有特别多类似这样的标记接口的设计方式,它们的存在就像是一种标签一样,可以方便统一摘取出属于此类接口的实现类,通常会有 instanceof 一起判断使用。
if a instanceof 某个具体的子类,则 do 对应的逻辑。