getBean对Spring来说,是一个非常重要的方法,用于实例化对象。比如在获取BeanProcessor的时候,就用到了beanFacroty.getBean来获取BeanProcessor对象。从doGetBean出发。
getSingleton
这边涉及到了几个类里面的参数先提及一下:
singletonObjects:用Map类型的该参数来存放beanName和bean实例之间的关系,bean的生命周期已结束(一级缓存);
singletonCurrentlyInCreation:正在实例化的单例;
earlySingletonObjects:提前暴露的单例实例,bean的生命周期还未结束(二级缓存);
singletonFactories:用Map类型的该参数来存放beanName和beanFactory之间的关系(三级缓存);
先从一级缓存中根据beanName拿值,如果拿到了就返回,没有拿到的话,先去判断下beanName代表的实例是否正在创建,如果是在创建中,那就去二级缓存中拿值,如果没拿到,就去三级缓存中根据beanName获取到BeanFactory对象,通过BeanFactory的getObject拿到实例,然后重新将值赋给二级缓存,再从三级缓存中移除beanName和其BeanFactory,如图1。
为什么需要这么麻烦设计三次缓存来获取实例,为什么不像自定义Spring一样只要用一个singletonObjects就能解决获取实例的问题?是因为我们在使用Spring的过程中,很多时候涉及到了循环依赖,本次只讲getBean,循环依赖下一次再讲。
如果getSingleton获取到了实例,还回去判断当前返回的是不是和工厂相关的(beanName有“&”前缀),如果是,但是并不是FactoryBean类型的就会报错。所以现在的获取到的实例要么是个正常的bean,要么是工厂bean。如果是正常的bean就直接返回,如图2:
如果是工厂bean,先去缓存中尝试获取bean,如果成功了直接返回,如果不成功,调用getObjectFromFactoryBean,如图3。
最终还是会通过调用doGetObjectFromFactoryBean方法里工厂的getObject操作获取bean实例,如图4:
不过一般第一次getSingleton是获取不到实例的,走的是else这条路线:
接下来就是看是否有父类工厂、dependsOn依赖于其他实例的创建,有的话要它们先创建,这边就不看了。往下看代码发现又出现了一个getSingleton方法,里面有四个比较重要的方法:
1、beforeSingletonCreation
该方法中有两个类参数:inCreationCheckExeclusions(排除正在创建检查的beanName的集合,这个集合目前遇到的比较少,知道有这个属性即可),以及singletonCurrentlyIncreation(这个集合里的都是正在进行实例化的bean,就是实例化还为完成的beanName,防止bean对象在进行循环依赖引用的时候反复创建)。往singletonCurrentlyIncreation中添加正在实例化的beanName。
2、singletonFactory.getObject()
通过工厂创建实例。
3、afterSingletonCreation
实例化完成后从singletonCurrentlyIncreation中删除对应的beanName。
4、addSingleton
二、三级缓存删除对应的beanName,一级缓存添加beanName和bean实例的对应关系,再往registeredSingletons添加beanName代表已经完成的bean实例化。
-----------------------------------------------------------------------------------------------------------------------------------
createBean
关注doCreateBean,如果是单例,尝试用beanName直接从之前的保存在factoryBeanInstanceCache中获取BeanWrapper,如果不行则调用createBeanInstnce来创建BeanWrapper(BeanWrapper是对bean的包装,是bean到BeanDefinition的中间产物,用来为bean做属性填充)。
createBeanInstance
用于生成BeanWrapper的方法,有三种实现:
1、如果当前BeanDefinition有instanceSupplier属性,就以此来生成BeanWrapper,在使用Spring的过程中,可以通过如图9所示来使用:
2、如果有factory-method属性,调用instantiateFactoryMethod生成BeanWrapper。
3、对于没有上面两个属性的,也可以通过构造函数进行实例化,分为有参构造函数和无参构造函数。有参构造函数先通过determineConstructorsFromBeanPostProcessors获取到含有@Autowired注解的构造函数,然后调用autowireConstructor生成BeanWrapper。无参构造函数直接调用instantiateBean生成BeanWrapper。
applyMergedBeanDefinitionPostProcessors
用来对类中的注解进行装配,是通过BeanPostProcessor的postProcessMergedBeanDefinition进行装配,列举下面两个比较重要的实现类:
CommonAnnotationBeanPostProcessor
这个类中的解析分为两部分:一个是postProcessMergedBeanDefinition来扫描@PostConstruct和@PreDestory注解;一个是findResourceMetadata来扫描@Resource注解。
postProcessMergedBeanDefinition:先根据beanType去缓存lifecycleMetadataCache中寻找LifecycleMetadata,如果未找到则通过buildLifeCycleMetadata找到里面的initMethod和的storyMethods方法,以及类本身,会被包装成LifeCycleMetadata对象,如图10,并放入缓存lifeCycleMetadataCache,如图11:
然后通过checkConfigMembers对当前的BeanDefinition进行扫描,把其中的initMethod和的storyMethod拿出来,放入类参数checkedInitMethods和checkedDestoryMethods中,如图12:
findResourceMetadata和checkedConfigMembers:和上面扫描初始化和销毁方法一样,也有一个缓存参数injectionMetadataCache,如果找不到也是要通过buildResourceMetadata构建,将里面有@Resource注解的元素放入injectedElements中,如图13,构建完后放入缓存,返回InjectionMetadata,如图14:
通过checkConfigMembers对当前的BeanDefinition进行扫描,把含有@Resource注解的属性或者方法拿出来,遍历的就是上一步存到类中的元素集合,然后放到类参数checkedElements中,如图15:
AutowiredAnnotationBeanPostProcessor
功能就是用来扫描方法或者属性上的@Autowired注解,通过buildAutowiringMetadata方法构建元数据,将其放入injectionMetadataCache缓存中。然后对BeanDefinition进行checkConfigMembers扫描,把含有@Autowired注解的属性或者方法拿出来,放到类参数checkedElements中,和上述方式差不多,如图16:
earlySingletonExposure
用来判断是否支持进行提前暴露操作,会根据当前BeanDefinition是否单例、是否允许循环依赖(一般允许),以及在singletonCurrentlyInCreation中是否存在当前beanName,如图17:
如果都符合条件,调用getEarlyBeanReference获取到提前暴露的实例,并且在三级缓存中添加beanName和单例工厂,移除二级缓存中提前暴露的实例,如图18:
populateBean
这是IOC/DI依赖注入的核心方法,直接拉下来看关于BeanPostProcessor的应用,如图19:
关注postProcessProperties方法,该方法是之前通过postProcessMergedBeanDefinition扫描注解并收集后对其元数据执行inject方法。以@Autowired为例,如图20:
首先根据beanName寻找到InjectionMetadata,通过element.inject方法对已经收集到的注解进行反射调用,比如注解在字段上,则会使用field.set(bean, value);在方法上,则会使用method.invoke(bean, arguements)。
对于在xml中配置的属性,如<property>标签内部属性的依赖注入,则是通过下面applyPropertyValues方法实现的,如图22,因为现在基于XML配置的很少使用了,就不必去看是怎么添加属性的。
initializeBean
这个方法是在实例化和IOC/DI注入后的操作,首先是对某些Aware接口的调用,如图23:
然后调用了applyBeanPostProcessorsBeforeInitialization对类中某些特殊方法的调用,也是会先通过beanName拿到元数据,然后通过invoke方法进行反射调用,如图24:
再是通过invokeInitMethods方法,对实现了InitializingBean的类中的afterProperties方法的调用:
最后调用applyBeanPostProcessorsAfterInitialization方法,和before一样,进行反射调用。
registerDisposableBeanIfNecessary
在bean创建完成后都会调用这个方法,因为用到的都是单例模式的,所以直接看如下代码:
DisposableBeanAdapter对象是来负责bean销毁的类,在new的时候会去扫描BeanDefinition中的destory-method属性,以及其余属性来构建对象,然后以beanName为key,生成的DisposableBeanAdapter对象为value,放进disposableBeans中。
----------------------------------------------------------------------------------------------------------------------------------
getObjectForBeanInstance
里面有个BeanFactoryUtils.isFactoryDereference方法,判断传进去的name是否携带了“&”作为name开头,只有工厂beanName才会有这种结构,但如果该实例不是FactoryBean,还是会抛出异常。如果没有携带“&”作为name的开头,并且不是FactoryBean,表明这是个普通实例,直接返回;如果是工厂实例,则需要调用getObject从工厂中生产实例后返回,上面已经有类似的流程了,就不截图了。
-----------------------------------------------------------------------------------------------------------------------------------
Prototype作用域的BeanDefinition
逻辑和单例的差不多,但是不像单例这么复杂,需要考虑重复创建的问题;多例作用域只要执行了createBean,就是一个新的实例,如图27:
-----------------------------------------------------------------------------------------------------------------------------------
埋点
在看源码的过程中我们经常看到如图28所示的代码,可以看出BeanPostProcessor接口类型是对具有某种特定功能的埋点,根据对当前的BeanPostProcessor进行instanceof判断,用来过滤掉功能不相关的BeanPostProcessor,然后执行特定的方法。
下面来看一下有哪些地方用到了这类埋点:
1、MergedBeanDefinitionPostProcessor:图28调用的方法是postProcessorMergedBeanDefinition,收集@Resource、@PostConstruct、@PreDestory、@Autowired、@Value注解的方法和属性。
2、SmartInstantiationAwareBeanPostProcessor:调用的方法是determineCandidateConstructors,用来获取@Autowired注解的方法和属性;而在循环依赖中解决bean提前暴露的实例,则是通过getEarlyBeanReference,如图29:
3、InstantiationAwareBeanPostProcessor:调用的方法是postProcessorAfterInstantiation,其中的continueWithPropertyPopulation为true代表可以进行依赖注入;postProcessProperties则是IOC/DI依赖注入的inject方法的埋点,如图30: