spring循环依赖解析(1)

在讲解循环依赖之前,首先看下普通的bean创建都执行了哪些基本流程,首先bean的实例化是在spring的refresh()方法中的倒数第二步finishBeanFactoryInitialization(beanFactory);

然后方法会执行到doGetBean中的getSingleton(beanName)中去寻找

那么这个时候就会先去一级缓存singletonObjects中去寻找,如果为null,那么这个时候就会继续判断isSingletonCurrentlyInCreation(beanName),意思就是这个bean是否在创建中,如果正在创建中就从二级缓存中earlySingletonObjects中去获取,如果再没有就去三级缓存也就是singletonFactory中去查找,此时如果在三级缓存中获取到,则将获取到的bean放入到二级缓存,并且将该bean从三级缓存移除;

二级缓存和三级缓存下面会慢慢讨论,先看下isSingletonCurrentlyInCreation这个方法,他就是判断当前要创建的bean是否正在创建中,因为spring对bean的创建不是像我们平时new一下直接就创建好,是分为几个步骤的(内存开辟,属性填充,对象初始化)等;

那么这个set是什么时候将bean放进去的呢?后面会看到

回到主线,我们对普通bean创建的时候,由于spring的缓存中没有获取到,此时就会去走到下面的逻辑,getSingleton的第二个属性值是一个方法体

点进getSingleton方法会看到以下四个点

1、beforeSingletonCreation(beanName)方法,这里就会把我们当前正在创建的beanName加入到set中,表示我们的这个bean正在创建,就跟上面衔接上了

2、singletonObject = singletonFactory.getObject()方法显然会调到外面的方法体,继续往里执行会走到doCreateBean方法,其中createBeanInstance这个方法是bean实例化核心方法,也就是把bean 实例化,并且包装成BeanWrapper

当然bean的实例化的方式也有多种

(1)、例如instantiateUsingFactoryMethod(beanName, mbd, args)这个方法是反射调用类中的factoryMethod 方法。这要知道@Bean 方法的原理,实际上 spring 会扫描有@bean 注解的方法,然后把方法名称设置到BeanDefinition 的factoryMethod 属性中,接下来就会调到上面截图中的方法实现@Bean 方法的调用。

(2)、有参构造函数的时候

determineConstructorsFromBeanPostProcessors,这个方法是BeanPostProcessor 接口类的首次应用,最终会掉到AutowiredAnnotationBeanPostProcessor 类的方法,在方法中会扫描有注解的构造函数然后完成装配过程。然后把有有@Autowired 注解的构造函数返回,并反射调用构造方法获取bean实例

(3)、无参构造函数的实例化

这就是简单的反射实例化。大部分类的实例化都会走这个逻辑

此时doCreateBean中创建bean实例的方法createBeanInstance(beanName, mbd, args)就结束了,我们继续向下看doCreateBean中的applyMergedBeanDefinitionPostProcessors方法

实例化完成后接下来就需要对类中的属性进行依赖注入操作,但是类里面属性和方法的依 赖注入往往用@Autowired 或者@Resource 注解,那么这些注解的依赖注入是如何完成的 呢? 注解的收集也是在这一步通过BeanPostProcessor 接口类型实例来挨个处理的。

(1)、CommonAnnotationBeanPostProcessor

首先是CommonAnnotationBeanPostProcessor 类,这个类完成了@Resource 注解的属性或
者方法的收集这个类还对@PostConstruct 和@PreDestory 支持。收集过程

1、看缓存里面有没有InjectionMetadata 对象

2、从类中获取所有Field 对象,循环field 对象,判断field 有没有@Resource 注解, 如果有注解封装成ResourceElement 对象

3、从类中获取所有Method 对象,循环Method 对象,判断Method 有没有@Resource 注解,如果有注解封装成ResourceElement 对象

4、最终把两个field 和Method 封装的对象集合封装到InjectionMetadata 对象中

(2)、AutowiredAnnotationBeanPostProcessor
然后是AutowiredAnnotationBeanPostProcessor 类,对@Autowired 注解的属性和方法的收集。收集过程基本上跟@Resource 注解的收集差不多

收集完注解之后,这里会将bean实例放入到三级缓存之中

继续向下是会执行populateBean方法(属性填充),initializeBean(初始化动作)

先看populateBean方法如下图,这里又是一个BeanPostProcessor 类型接口的运用,前面我们讲到了 @Resource@Autowired 注解的收集,那么这个方法就是根据收集到的注解进行反射调 用。

循环收集到的metaData 中的list 对象,然后挨个调用里面的InjectedElement 的 inject 方法完成依赖注入。

其中value 值的获取,如果依赖的属性是一个引用类型必定会触发该属性的 BeanFactory.getBean 操作,从而从spring 容器中获取到对应的实例。方法的依赖注 入类似这里就不再赘述

bean属性填充后的操作即是方法initializeBean

(1)、首先是对某些Aware 接口的调用

(2)、然后@PostConstruct 注解方法的调用

这里又是一个BeanPostProcessor 接口的运用, 前面讲过,有@PostConstruct 注解的方法会收集到一个metaData 对象中,现在 就是通过BeanPostProcessor 接口调到 CommonAnnotationBeanPostProcessor 类,然后在类中拿到metaData 对象, 根据对象里面的容器来反射调用有注解的方法。代码如下:

有@PostConstruct 注解的容器会收集到initMethods 容器中,接下来就是方法的反射调用。

(3)、InitializingBean 接口和init-method 属性调用

实现了InitializingBean 接口的类就必然会调用到afterPropertiesSet,Init-method 属性调用是在afterPropertiesSet 之后

在initializeBean这个方法里面还有一个重要的逻辑也是一个BeanPostProcessor 接口的运用,在这里会返回bean 的代理实例,这个就是AOP 的入口,后面的章节会讲解到。

doCreateBean方法的最后一步,也就是完成初始化之后,会注册一个bean销毁的回调方法,当bean销毁的时候会调用这个方法

3、afterSingletonCreation(beanName)方法,程序执行到这里说明bean已经创建完毕,会将beanName从singletonsCurrentlyInCreation中移除

4、addSingleton(beanName, singletonObject),将创建好的bean放入到一级缓存中,并根据beanName将bean从二级缓存,三级缓存中移除

至此,单个bean的完整创建流程讲解完毕,由于本章篇幅太大,作为讲解循环依赖的基础,下一章开始正式讲解循环依赖

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值