一起来读Spring源码吧(二)容器getBean过程详解
上一篇分析了XmlBeanFactory的初始化过程,此时配置的bean已注册到容器中,但也仅仅只是保存了bean的信息,并没有产生bean实例。下面我们以BeanFactory.getBean(String name)为出发点探索下bean的加载过程。
AbstractBeanFactory实现了getBean方法,调用doGetBean真正开始获取bean。
首先是将参数name转化为beanName,如果是“&”开头的代表是FactoryBean(是特殊的bean,后面会讲到)需要把“&”去除;如果是别名就去寻找它最终指向的beanName。
然后从容器的单例注册中心尝试获取bean实例。顺序如下:从单例缓存中(容器的singletonObjects属性)尝试获取;如果没有就从提早曝光单例对象(容器的earlySingletonObjects属性)尝试获取;如果还没有,就从singletonFactories中尝试获取这个bean的ObjectFactory,再调用ObjectFactory.getObject()获取到bean,放入earlySingletonObjects,把ObjectFactory从singletonFactories中移除(是不是很混乱?别急,这是Spring为了避免循环依赖做出的策略,后面我们会解释)。
如果没有获取到,也就是说要新建一个,先检查bean是否已经在原型创建中(避免原型的循环依赖),再在容器中查找是否存在beanName对应的BeanDefinition,找不到的话就递归从父容器查找;然后如果BeanDefinition有依赖(也就是bean定义时有depends-n属性)就先把依赖关系注册到容器的dependentBeanMap,再递归加载依赖的bean;然后根据BeanDefinition设置的scope选择创建单例、原型还是其他scope的bean实例。单例的话调用getSingleton创建单例;原型的需要先把beanName注册到容器的prototypesCurrentlyInCreation中(为了防止循环依赖)然后调用createBean创建bean实例,随后从prototypesCurrentlyInCreation找中移除beanName。创建出的实例跟前面在缓存中获取到的一样并不会直接返回,而是调用getObjectForBeanInstance,如果不是FactoryBean或者想要的就是FactoryBean本身(name是&开头)就直接返回;否则先从工厂创建bean缓存factoryBeanObjectCache中尝试获取,没有就调用getObjectFromFactoryBean方法创建一个bean实例(是单例还会存入factoryBeanObjectCache)返回。一大堆流程看下来是不是有点晕,让我们再来简述下步骤:
1、name转化为beanName
2、尝试从缓冲中获取单例
2.1、单例缓存singletonObjects中查找(这个getSingleton只查找不创建)
2.2、提早曝光单例earlySingletonObjects中查找
2.3、singletonFactories中查找ObjectFactory并在生产bean放入earlySingletonObjects后移除
3、缓冲中获取不到,需要新建
3.1、当前容器中查找BeanDefinition
3.2、没有的话去父容器中查找BeanDefinition
3.3、递归加载设置过的依赖bean
3.4、根据scope创建bean实例
4、如果是工厂bean,返回生产的bean
4.1、尝试从缓存factoryBeanObjectCache中获取
4.2、调用BeanFactory.getObject()生产一个bean实例
4.3、如果不是应用程序本身的bean,调用后置处理器(这个后面会重点说)
4.4、是单例的话存入factoryBeanObjectCache
现在我们大致了解了向容器获取一个bean的主要步骤,但是我们还是不太清楚具体是怎么创建bean实例的,所以我们还需要继续深入:
前面说到如果是单例的话,调用getSingleton(String beanName, ObjectFactory<?> singletonFactory)(区别于2.1的getSingleton),先从singletonObjects查找,没有的话将beanName放入singletonsCurrentlyInCreation表示该bean正在加载;然后用参数singletonFactory的函数方法createBean(对,就是和原型一样的那个)创建一个bean;将beanName从singletonsCurrentlyInCreation中移除;最后将新建立的beanName和bean的映射关系保存到缓存singletonObjects和已注册registeredSingletons中,移除singletonFactories和earlySingletonObjects中的记录。步骤简述如下:
3.4.1、从singletonObjects查找
3.4.2、设置正在加载状态
3.4.3、createBean创建bean
3.4.4、移除正在加载状态
3.4.5、保存缓存,删除中间辅助状态
我们再来看createBean。先从BeanDefinition中获取bean的Class,再对override属性(通过lookup-method和replace-method配置,后面实例化时会用到)进行标记和验证,然后给后置处理器一个机会直接返回bean代理,即如果容器中有注册InstantiationAwareBeanPostProcessor这类后置处理器的话,就分别执行它的postProcessBeforeInstantiation和所有后置处理器的postProcessAfterInstantiation,如果返回不为空就直接返回代理bean(AOP功能基于这里判断的);最后调用doCreateBean实例化bean。步骤简述如下:
3.4.3.1、从BeanDefinition中获取bean的Class对象
3.4.3.2、对override属性进行标记和验证
3.4.3.3、初始化前的短路判断
3.4.3.4、实例化bean
继续深入doCreateBean,第一步判断如果是单例的话从factoryBeanInstanceCache中获取缓存的BeanWrapper(bean的包装类)并从中移除,如果没有则调用createBeanInstance创建一个BeanWrapper;然后应用MergedBeanDefinitionPostProcessor(AutowiredAnnotationBeanPostProcessor,Autowired);允许循环依赖的并且自身在创建中的单例,把此单例的ObjectFactory(SmartInstantiationAwareBeanPostProcessor,AOP)注册到singletonFactories,同时从earlySingletonObjects移除对应;然后调用populateBean对bean的属性进行填充,递归初始依赖的bean;再调用initializeBean执行初始化方法;对于允许循环依赖的并且自身在创建中的单例做循环依赖检查;最后注册DisposableBean。步骤简述如下:
3.4.3.4.1、尝试从factoryBeanInstanceCache中获取缓存BeanWrapper
3.4.3.4.2、创建一个bean实例返回BeanWrapper
3.4.3.4.3、应用MergedBeanDefinitionPostProcessor
3.4.3.4.4、依赖处理
3.4.3.4.5、属性填充
3.4.3.4.6、执行初始化方法
3.4.3.4.7、循环依赖检查
3.4.3.4.8、注册DisposableBean
首先我们看如何创建一个bean实例。先是解析出Class,如果工厂方法不用空,即设置了factory-method,则使用工厂方法初始化策略;否则需要根据参数锁定构造函数,如果已经解析过了在缓存中可以找到锁定,否则进行解析锁定并加入缓存;没有锁定到有参数的构造函数的话,就使用默认构造器,如果有需要覆盖或动态替换的方法(override属性)需要使用CGLIB进行动态代理,否则就用反射的方式创建实例。
再来看一下属性填充。在属性设置前应用InstantiationAwareBeanPostProcessors的postProcessAfterInstantiation(可以控制是否继续填充),然后根据设置的自动注入方式(名称或者类型)获取属性bean(递归getBean)存入PropertyValues中,再应用InstantiationAwareBeanPostProcessors的postProcessProperties对填充前的属性进行处理(如对属性的验证),最后将所有PropertyValues中的属性填充到BeanWrapper中。
属性填充完之后就是initializeBean方法了。首先对实现XXAware接口的bean注入相应的资源(如实现了BeanFactoryAware的bean会注入当前BeanFactory的实例),然后就是注册了的BeanPostProcessor的postProcessBeforeInitialization,再是激活自定义的init方法,先后执行实现了InitializingBean的afterPropertiesSet方法和配置init-method方法。
最后看下DisposableBean的注册。注册DisposableBean的实现,在注销时执行来源于DestructionAwareBeanPostProcessors、实现的DisposableBean的destroy方法还有自己配置的destroy-method的处理。