今日份重点掌握:扫描注解并放入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对象的?通过反射的形式生成了这个对象。