提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
正式开始前,咱们先重温下背景知识。实例最终都是存放在BeanFactory中,BeanFactory也是有层级关系的,比如当前BeanFactory可能有parentBeanFactory。在完成BeanDefinition注册之后,BeanFactory中还没有BeanInstance。因此,当第一次获取BeanInstance时,将触发BeanFactory对BeanInstance的初始化。此外,对于有继承关系的Bean,在初始化BeanInstance时,需要对父类中的属性,构造方法做必要的处理。最后,BeanFactory中对单例是有特殊处理的,在代码细节上会把singleton和其他scope的逻辑分开。
本文基于易于理解的原则,尝试借助于多层容器中查询元素的思路,让整个过程理解起来就像你自己设计的一样。
一、建立视图
如果你想知道山下的路到底该怎么走,那你最好有一个上帝视角,能够将所有的山路一览无余。探索Bean加载过程就好比是走山路,层峦叠嶂,很容易迷失在细节中。因此,在进入这群山之前,建立一份地图很关键。对于程序而言,一开始甚至不需要一些特别精细的地图,因为程序是有目的性的,当你明确了目的时,这份地图已完成了一半。反复运行“由A、B可以得到C,由A、B、C可以推理出D”这个过程,你就可以用假设,推理,验证完成整个地图的绘制。
举个栗子,考虑到BeanFactory是有层级,所以最终的BeanFactory层级结构可能是这样的:
有点类似数据结构中的树,如果你数据结构玩的溜,一般也就考虑三个层级的问题,然后把规律推广到整棵树。这其中就体现了化简。咱们能否再化简下呢?
我们的目的是在某个BeanFactory中找到某个BeanDefinition,所以要么在当前BeanFactory中寻找,要么在parentBeanFactory中寻找。此外在OOP中,最小依赖原则,当前BeanFactory仅知道parentBeanFactory不知道grandParentBeanFactory,也不需要知道brotherBeanFactory。于是简化从3个节点简化为2个节点,再把singletonBean和otherBean添加上,大概长这个样子:
二、顺藤摸瓜
定位BeanFactory
基本思路
其实前面已经聊到了,首先在当前BeanFactory中查找,如果找不到,再去parentBeanFactory中查找。不过,考虑到BeanName的唯一性,顺序需要调整为先parent再current。但在Spring的实现是这样的:
- 查找currentBeanFactory的singleton中是否存在,如果存在则返回;
- 查找parentBeanFactory中是否存在beanName, 如果存在则从parent中获取;
- 在currentBeanFactory创建BeanInstance;
这里有个问题,先parent再current应该是最先判断的,结果放在了singleton之后?
误差解释
个人理解有2个,
(1)singleton默认都是放在当前BeanFactory中,个人自扫门前singleton;
(2)在初始化的时候,Spring并没有先判断给定的beanName是singleton还是其他。而是singleton中有就做进一步初始化,singleton中没有就从头初始化。这里的singleton有点儿类似缓存的作用。
获取BeanDefinition
- 对于没有继承关系的Bean,这里直接从BeanFactory中的beanDefinitionMap中获取对应的BeanDefinition并转换为RootBeanDefinition即可。
- 对于有继承关系的Bean,也就是BeanDefinition中parentName != null,需要把parentBeanDefinition中的属性合并到当前BeanDefinition中,并使用currentBeanDefinition中的值覆盖parentBeanDefinition中的值。如此屏蔽继承对BeanInstance创建逻辑的逻辑影响。
最终通过getMergedBeanDefinition(),获得目标BeanName的RootBeanDefinition
依赖Bean处理
- 通过两个map维护双向依赖关系。在dependencyMap中注册当前Bean的依赖者,在dependentMap中注册当前Bean的被依赖者。至于为什么需要维护依赖?当前初始化阶段需要先初始化依赖bean再初始化当前bean,后续Bean释放阶段需要先释放当前bean再释放依赖的bean。这就是地图虽然不精确,但是我们可以站在实现目的背景下假设,推断和验证。
- 对依赖者做初始化,初始化过程和当前初始化过程类似,直接递归调用即可;
三、获取BeanInstance
1. 外围烟雾弹
(1)对于singleton直接缓存,没有前置处理;
(2)对于prototype和自定义scope,有一个beforePrototypeCreation和afterPrototypeCreation;至于自定义Scope,通过BeanFactory的registerScope做注册,暂时先不深究;
(3)对于FactoryBean,还需要调用getObject()方法获取目标对象,这部分逻辑在getObjectForBeanInstance中完成;
核心代码如下:
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
2. 实例化BeanInstance
- 在RootBeanDefinition中处理methodOverride;
- 初始化前处理,也就是InstantiationAwareBeanPostProcessor。此处注意,如果postProcessorBeforeInstantiation方法返回一个object对象将阻断后续初始化过程,然后执行InstantiationAwareBeanPostProcessor中的applyBeanPostProcessorsAfterInitialization函数。因此postProcessorBeforeInstantiation在实现上需要注意这个细节。
- 确认bean class正常加载;
- 确定创建实例的方式,构造函数or init-method。如果也设置了SmartInitializeAwareBeanPostProcessor,也可以从中确定构造函数
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName) throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
return null;
}
- 通过实例化策略,执行实例化。实例化策略的实现有两个,SimpleInstantiationStrategy和CglibSubclassingInstantiationStrategy。前者就是通过BeanUtil完成实例创建。后者则根据情况创建必要的代理类。显然,如果希望了解动态代理,这里就是入口;这里我们暂不深入。
- 到这里就完成了实例的早期创建。所谓的早期创建类似于new 操作符返回,但其中的属性什么的还没设置;
3. 初始化BeanInstance
- MergedBeanDefinitionPostProcessor
- 对于singleton,通过ObjectFactory暴露早期对象;
- 设置AUTOWIRE属性,或者声明的依赖;
- 对于InstantiationAwareBeanPostProcessor,调用postProcessProperties,对属性值做必要的处理。注意这些属性目前还没设置到property中;
- 设置BeanDefinition中定义的属性值;
- 后续的处理就比较常见了。个人对其做了一些分类,帮助你理解;
aware方法
(叫啥名)BeanNameAware#setBeanName
(从哪儿来)BeanClassLoaderAware#setBeanClassLoader
(住哪里)BeanFactoryAware#setBeanFactory
环境相关方法
(什么环境下的)EnvironmentAware#setEnvironment
(怎么找内部值)EmbeddedValueResolverAware#setEmbeddedValueResolver
(怎么找外部Resource)ResourceLoaderAware#setResourceLoader
应用上下文ApplicationContextAwareProcessor#postProcesBeforeInitialization
(应用事件发布)ApplicationEventPublisherAware#setApplicationEventPublisher
(消息源)MessageSourceAware#setMessageSource
(应用启动对象)ApplicationStartupAware#setApplicationContext
(应用上下文)ApplicationContextAware#setApplicationContext
自定义初始化逻辑
afterPropertiesSet
init-method
后处理逻辑
所有的postProcessAfterInitialization
4. 销毁逻辑注册
BeanDestructionAware#postProcessBeforeDestruction
DisposeBean#destory
自定义destory method
最后返回最终初始化完成的BeanInstance。
总结
以上就是Bean实例获取的全部内容,在获取过程中涉及的待定问题较多,在后续的文章会以专题的形式做进一步的探讨。虽然Spring中提供的扩展层次有很多,但是日常的应用开发中使用比较多的是初始化阶段的aware方法,afterPropertiesSet,init_method和自定义destory-method。Spring生态下的其他扩展组件大部分对BeanPostProcessor都有依赖。总得来说,各层次的预留接口为后续的扩展提供了广阔的空间。
最后,感谢你的阅读,如果本文对你有所帮助,欢迎留言评论拍砖吐槽。