在讲解循环依赖之前,首先看下普通的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的完整创建流程讲解完毕,由于本章篇幅太大,作为讲解循环依赖的基础,下一章开始正式讲解循环依赖