Spring源码解析(一):扫描注解并放入IOC容器(呕心沥血之作,大家耐心看完,很有帮助!!!)

tech2022-07-08  195

今日份重点掌握:扫描注解并放入IOC容器

我们先不谈怎么将外部的对象放入IOC容器,我们先讲一个问题,这个问题是什么呢?就是我们的注解来了之后,如何实现扫描,以及,最终是怎么将这个对象放到我们的容器中去的。

实际上,最终调用的是refresh这个方法(register先不管,后面会谈),我们先进入refresh这个方法

在refresh这个方法中(以下方法供了解)

重点来了!!!真正实现对象实例化的是这个方法:

也就是说,我们拿到这个对象,生成对象,放到我们的容器里面去。

那么......问题来了

他是怎么生成对象的???是通过new吗?对象拷贝吗?反射吗?我们先把问题抛在这里,慢慢为大家做出解答

实例化所有对象,并且是 非懒加载的 和 单例的 对象。所以我们总结,单例的才会被创建并放入对象,多例则不会。

 

下一步,我们进入 finishBeanFactoryInitialization 这个方法一探究竟

这个方法是实例化bean的,前面有很多if进行校验、配置,这些我们不管

校验完成之后,真正实现实例化的是这句话 beanFactory.preInstantiateSingletons();

我们再进入这个方法

他把每一个类扫描出来之后,都会有一个名字,将这些名字存入ArrayList这个集合中,进行遍历、合并。

为什么要合并呢?判断当前生成的BeanDefinition是不是RootBeanDefinition的子类(这样进行理解),实际上是为了高低版本的兼容,因此进行合并。合并到RootBeanDefinition,因为这是最大的父类

 

拓展知识:GenericBeanDefinition (高版本中出现)是一个通用的 BeanDefinition,他和 RootBeanDefinition(低版本中出现) 属于同一个级别,都是用于描述被扫描到的类

 

回归主线,真正的初始化一个bean是调用的getBean方法,为什么是getBean呢?这个方法的意思不是获取bean吗?

此处方法共用了,无论创建bean还是获取bean,都调用getBean这个方法

进入这个方法,传入一个名字,调用doGetBean方法

我们再进入doGetBean这个方法

进入getSingleton方法

再进入getSingleton方法,这里的意思是通过名字调用这个单例对象

我们再看这个singletonObjects到底是个什么鬼

没错,它就是一个ConcurrentHashMap对象,这就是IOC容器存放对象的单例池。也就诠释了我们第一个问题,什么是IOC容器。

但是,我们还是没有解决第二个问题,它是怎么创建对象的???

 

我们再看向AbstractBeanFactory这个类,第334行代码,真正的创建bean在这里

我们进入createBean这个方法

继续往下看,第506行代码,这里才是真正创建bean的位置

我们进入doCreateBean这个方法看看,这句话的意思是,推断bean的构造方法,实例化对象

进入createbeanInstance方法

大家发现没有,我已经说了N次 真正实例化bean对象的代码

别急

往下看

我们进入instantateBean这个方法

进入instantiate这个方法瞧瞧

还是没有我们想要的最终答案,继续进入instantiateClass这个方法

山穷水复疑无路,柳暗花明又一村

这个ctor.newInstance(args)这个就是我们的最终解,没错了,实例化bean的方式为 反射 !!!

 

 

讲了这么多,我们来总结一下

IOC容器是什么?

实际上就是concurrentHashMap<key,value>单例池。其中,key是当前bean对象的名字,value是bean对象。

最终是怎么生成bean对象的?通过反射的形式生成了这个对象。

最新回复(0)