IOC原理解读(二)
继上篇
今天解读的是:
基于xml配置的bean的IOC过程中的实例化跟依赖注入原理。
xml配置文件spring-bean.xml内容如下:
在加载完各个bean的definition到一个beanDefinitionMap后,是如何实例化bean呢?
先看看那些地方在需要获取bean definition,从这里找入口
1、查看获取definition的方法是哪被调用的
在AbstractBeanFactory类中看到具体调用
然后在doGetBean方法中找到了
然后终于找到了 是AbstractBeanFactory 类中的 getBean(String name) 是真正调用的地方
然后在AbstractApplicationContext中找到了调用
同类中调用
同类中调用(beanFactory 在refresh方法中始终贯穿)
看到这,我们大致知道了,实例化bean跟依赖注入的流程
Spring IoC容器对Bean定义资源的载入是从 AbstractApplicationContext 的 refresh() 函数开始的
refresh()是一个模板方法,refresh()函数的作用在于:在创建Ioc容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。
refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。
AbstractApplicationContext
refresh中的具体步骤
1、准备刷新此上下文;
2、告诉子类刷新内部bean工厂;
3、准备bean工厂以便在此上下文中使用;
4、允许在上下文子类中对bean工厂进行后处理;
5、调用上下文中注册为bean的工厂处理器;
6、注册拦截bean创建的bean处理器;
7、为此上下文初始化消息源;
8、为此上下文初始化事件多主机;
9、初始化特定上下文子类中的其他特殊bean;
10、检查侦听器bean并注册它们;
11、实例化所有剩余(非lazy init)单例;
第二个参数false代表,这次加载的没有排除单例的bean定义,根据这些bean的名字,获取bean,实例化bean,并且在实例化过程中完成依赖注入
12、最后一步:发布对应事件;
下面我们看看具体是如何对bean进行实例化,然后完成依赖注入的
先看是如何完成所有需要实例化对象的实例化的
doGetBean方法
//这里是实际取得Bean的地方,也是触发依赖注入的地方
先不着急,看看具体实例化是如何操作的(也就是doGetBean())?逐个实例化
如果有依赖的对象,那么将依赖的对象全部实例化!直到逐层依赖的对象,全部创建成功为止。
getBean是依赖注入的起点,之后会调用createBean,下面我们分析createBean的代码
doCreateBean方法
createBeanInstance方法
跟随上面的步伐,上面实例化的时候调用了instantiateBean方法,该方法代码如下:
我们重点关注 getInstantiationStrategy() 这个方法,可以看到instantiateBean方法的功能实现是通过调用getInstantiationStrategy().instantiate方法实现的。
getInstantiationStrategy 方法的作用是获得实例化的策略对象,也就是指通过哪种方案进行实例化的过程。继续跟踪下去我们可以发现,Spring当中提供了两种实例化方案: BeanUtils 和 Cglib 方式。
BeanUtils实现机制是通过Java的反射机制,Cglib是一个第三方类库采用的是一种字节码加强方式机制。
Spring中采用的默认实例化策略是Cglib。
重点关注如下方法
如果没有重写,则不要用cglib重写类
其他地方没有改变当前对象的方法逻辑(没有被重写)
存在重写的方法就用Cglib
为什么?
正确解释如下:跟lookup-method注入和replace-method注入有关 见:
https://www.smwenku.com/a/5b9959102b717757338f4b18/
https://blog.csdn.net/lyc_liyanchao/article/details/82432993
Java 反射机制 创建对象
使用Cglib API 实例化对象
然后讲解注入依赖
看了上面的代码后,我们应该重点关注 createBeanInstance() 和 populateBean() 这两个方法。其中,populateBean() 开始 就是注入依赖
注入依赖
1、填充bean对象
2、暴露对象;
至此,终于完成了 实例化、依赖注入