Spring Framework海报
友情提示,图在最底部。
标题所指的海报是指类似CheatSheet的可打印手册,比如极客时间出的的知识地图或知识手册。
- 便于理解。一图胜千言,有了全局的知识地图,就可以从整体上把握,避免迷失在细节中。对于Spring框架这种庞大的设计显然更是如此;
- 转换角度。小册是从源码解析的角度来分析Spring。但是普通开发者通常接触不到Spring的底层细节,反而更关心如何使用。因此,我们最需要掌握的是Spring框架提供的扩展点,以及这些扩展点在整个执行流程中的位置。所以,一个好的全局图应该跳脱源码,体现运行期的逻辑流。 上面的ASP.NET海报就是典型;
- 易于记忆。陈皓分享过“知识压缩”的概念。一门知识如果细节太多,是不可能记得住的。把知识学会之后做个压缩,提取核心精华,就可以长久地保存在大脑里。具体的细节在使用时再查阅资料即可。
另外,由于Spring的范围太大了,因而不可能放到一张图里去。类似
ASP.Net Web Api
的海报应该对应的是Spring MVC。
网上搜集篇
首先我在网上搜罗了一圈,发现国外很少有人研究Spring内幕。看来还是国内比较卷~
全局图
下面这个图接近一幅完整的海报,但是偏介绍,帮助不大。
时序图
这篇文章总结的比较好。缺点是类和步骤太多,记不住。
下面是一些补充。
生命周期&扩展点
下面的几个图聚焦于Bean的生命周期:
这个图区分了生命周期的阶段,但内容不足。
这个图区分了类和方法的颜色,不过缺少注释。
这个图则对相同的类采用了同样的颜色。
这几个图的缺点是类似的:偏文字化,不符合开篇提到的几点要求。既然没有满意的,那就自己来吧。
闭门造车篇
首先,我们先用文字整理一下的Bean生命周期,关注逻辑流程和扩展点。
Bean的生命周期可以分为以下几个阶段,其中初始化阶段被细分为了实例化和初始化。
- 创建BeanDefinition阶段
- Bean的实例化
- Bean的初始化
- 运行期
- Bean的销毁
创建BeanDefinition
- 对于XML配置,就是在refresh()的第2步obtainFreshBeanFactory()中,最终调用XmlBeanDefinitionReader读取配置,注册BeanDefinition.
- 对于注解配置,就是在refresh()的第5步invokeBeanFactoryPostProcessors()中,最先调用了
ConfigurationClassPostProcessor
的postProcessBeanDefinitionRegistry
方法,该方法会扫描注解。 - 当然,可以定义其它的BeanFactoryPostProcessor,以对创建出来的BeanDefinition做修改。扩展点1
Bean的实例化(就是new出对象)
- 入口是refresh()的第11步,finishBeanFactoryInitialization().
- 最终会调用到AbstractBeanFactory的getBean()和doGetBean()方法
- 先会做循环依赖的处理
- 接着调用AbstractAutowireCapableBeanFactory#createBean()
- 先给InstantiationAwareBeanPostProcessor一个机会,直接拦截实例化过程 扩展点2
- 否则进入doCreateBean(),先调用createBeanInstance() 创建实例
- 如果BD指定了supplier 或factoryMethod,则直接调用
- 否则,找到合适的constructor并使用它创建实例。创建实例可以使用java反射,或cglib. 如果有参数则先搞定参数。此处有个SmartInstantiationAwareBeanPostProcessor的扩展,可以指定使用哪个constructor。扩展点3
Bean的初始化
- doCreateBean继续,先收集Bean的注解信息,如有必要就提早暴露Bean,以解决循环依赖
- 调用populateBean()进行属性赋值+依赖注入:
- 先回调InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法,在设置属性之前调用 扩展点4
- (根据name或type)自动注入属性,得到一个PropertyValues对象,再回调InstantiationAwareBeanPostProcessor的postProcessPropertyValues()和postProcessPropertyValues()方法,可以再修改属性数据。 扩展点5 这里有个重要的实现类AutowiredAnnotationBeanPostProcessor,它会做自动注入,通过反射的方式设置bean的字段
- 接着调用applyPropertyValues(),把pvs应用到Bean对象上。最终也是通过反射。
- 接着调用initializeBean(),进行初始化。这里面一共有4步
- 调用Aware接口(比如BeanNameAware)
- 调用各种BeanPostProcessor的postProcessBeforeInitialization()。其中某些BeanPostProcessor会调用@PostConstruct标注的方法 扩展点6
- 调用InitializingBean接口的afterPropertiesSet()方法和自定义的init-method 扩展点7
- 回调各种BeanPostProcessor的applyBeanPostProcessorsAfterInitialization() 方法。AOP就是在这里实现的。扩展点8
- 最后一步,是注册DisposableBean
- 最后,在应用启动时,会调用所有实现了Lifecycle的start()方法 扩展点9
Bean的销毁
- 先是容器的stop,调用所有Lifecycle的stop(),对应之前的start() 扩展点10
- 接着是容器的close(),重要的方法是destroyBeans(),销毁所有的bean。其中会调用@Predestroy、 DisposableBean的destroy()方法、destroy-method方法。扩展点11
- 最后丢弃BeanFactory。
做完这一步,我们至少已经把知识结构化了。接下来就是对着文字画图。
图来了
可以打印出来随手参照。
总结
有了最核心的Bean生命周期全景图,Spring的其它工作过程都可以对照着看了。后续如有必要,我会补充一些其它模块的海报。欢迎拍砖。
转载自:https://juejin.cn/post/6956814839729618957