Spring的Bean存储探讨
上文猜想Bean在Spring存储,这篇文章就带着之前的猜想,进入源码中一一验证。
上文猜想
源码编译
如何找到Spring存储的容器
不知道你是否使用过操作Spring容器的工具类,在一些非SpringBean的对象里面,要使用Bean对象时,就没办法使用@Resource或者@Authorware注解注入。这是就需要使用SpringUtils.getBean(Clazz.class)来获取Bean对象。比如:(可以随便找一个,可能看到的实现类不相同,但是继续往里面看一点是一样的(容器肯定是同一个)))
1、从日常使用找到入口
2、ConfigurationListableBeanFactory
既然我们这里使用到的是ConfigurationListableBeanFactory,那我们就从这个里面分析。
从beanFactory.getBean(name)进去之前,你会发现进入到了BeanFactory接口,作为Bean的工厂,那是不是Bean的创建、存储、使用都是由这个来控制呢?
那我们接着看BeanFactory的实现类(看这个的实现类你会发现非常多,如果是第一次接触Spring源码的建议先找些视频学习下)。根据我们的经验,我们可以进入到ConfigurationListableBeanFactory接口查看实现类,getBean方法的实现肯定在对应某个实现类里面。
这样我们就找到了DefaultListableBeanFactory。既然找到了入口,那么接下来就是进入源码中的(但是不要忘记我们的任务,当前只是为了找寻对应容器而已,不要陷入其他逻辑中,不然很容易晕车-从入门到放弃)。
3、DefaultListableBeanFactory
第一个,我们进入到了DefaultListableBeanFactory中,查看对应的getBean方法。
4、DefaultListableBeanFactory.resolveBean()
这个没啥特殊的,方法里面很简单,然后就来到了resolveBean方法:这个方法咋一眼看,一脸懵逼,其实你看它的return,在结合Spring只有一个容器,我们随便找一个应该都能找到容器。
我们就选第一个return方法进入查看:这里面就主要三段代码,三段代码都和candidateNames有关。
String[] candidateNames = getBeanNamesForType(requiredType);
看这段代码,意思也非常明确:根据类型获取Bean的名称。那么并没有获取到真正的Bean对象。继续想办法找。
从return找到关键信息,找到getBean方法才是获取一个实例对象,然后返回:
5、AbstractBeanFactory.getBean()
接着看doGetBean(我这里的代码收起来了,只展示了一些关键逻辑):重点在getSingleton:获取单例的Bean
6、DefaultSingletonBeanRegistry.getSingleton():
我们先不分析这段代码逻辑,可以看到最后的bean对象是从singletonObjects、earlySingletonObjects、singletonFactories这里面取出来的。说明最终的Bean是存储在这些里面。那么跟我们之前的猜想基本一致,以Map的形势存储在内存当中。那么到这里关于Bean存储的猜想和验证基本上就结束了。
这里其实就是常常说的Spring的三级缓存,以及如何解决循环依赖问题的主要逻辑。我们后续在详细分析。
韩楚风: 优质好文,博主的文章细节很到位,兼顾实用性和可操作性,感谢博主的分享,期待博主持续带来更多好文