您的位置:首页 > 编程语言 > Java开发

Spring3.1.0实现原理分析(七).填充Bean属性,初始化Bean,登记善后处理,注册单例Bean

2017-05-08 00:00 726 查看
大家好,上篇博客我较详细分析了实例化过程,今天继续探讨实例化之后的其它步骤,分别是“填充Bean属性”,“初始化Bean”,“登记善后处理”,“注册单例Bean”,加之实例化,这五个步骤是Spring创建对象的一个完整过程。

一. 填充Bean属性

<bean id="zoo" class="Zoo">
<property name="zooName" value="zooName" />
<property name="cat" ref="cat" />
</bean>

<bean id="cat" class="Cat"></bean>

在已获取到对象实例的基础上,这个阶段的任务就是为Bean的属性赋值,比如上图的定义,需要为zoo对象的两个属性“zooName”和“cat”赋值。具体的步骤如下,

1). 首先通过RootBeanDefinition对象的MutablePropertyValues getPropertyValues()方法,获取待赋值给bean属性的属性值集合对象。

2). 然后给予实例化敏感bean后处理器(InstantiationAwareBeanPostProcessor)有机会修改bean实例,调用boolean postProcessAfterInstantiation(Object bean, String beanName)方法对bean实例执行后处理。PS:在Spring启动阶段已经完成了对所有bean后处理的创建和注册,这块内容后续博客会分析。

3). 处理自动装配,前提是用户配置了自动装配策略(BY Name or By Type),默认是禁止自动装配的,并且自动装配也不支持基本类型(诸如Integer、String等)。所谓自动装配就是不需要显式为属性指定值,Spring自动根据属性名称或属性类型,找寻恰当的bean对象为其赋值。经过这个步骤,待赋值给bean属性的属性值变多了。

4). 再次调用实例化敏感bean后处理器,使其有机会在把属性值赋值给bean属性之前,再次执行后处理。这次调用的是后处理器的

PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)

方法,从第一个方法参数可以看出,本次后处理主要是针对待赋值给bean属性的属性值的。

5). 对属性值执行解析。

可以参考上篇博客的这段论述。



6). 把属性值赋值给bean对象。

通过Bean包装器实现该能功能,在Spring内部对bean属性的存取都是通过BeanWrapper实现的,具体可以参看这篇博客。《Spring3.1.0实现原理分析(四).属性访问器(PropertyAccessor)》

BeanWrapper.setPropertyValues(MutablePropertyValues);


二. 初始化Bean

1). 判断bean对象是否实现了Aware相关接口。

a. 如果bean对象实现了BeanNameAware接口,则调用bean对象的setBeanName(String)方法,意味这bean对象可以获取自身的Id。

b. 如果bean对象实现了BeanClassLoaderAware接口,则调用其setBeanClassLoader方法,bean对象可以获取bean工厂的类加载器。

c. 如果bean对象实现了BeanFactoryAware接口,则调用其setBeanFactory(bf)方法,bean对象可以获取bean工厂。

2). 调用所有bean后处理器的如下方法,在初始化之前对bean执行后处理。

Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

3). 初始化bean

如果bean实现了InitializingBean接口,则先调用该接口的void afterPropertiesSet() 方法。其次,如果用户配置bean时指定了init-method="..."属性值,则调用该方法对bean执行初始化操作。

4). 再次调用所有bean后处理器的如下方法,在初始化之后对bean执行后处理。

Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;


三. 登记善后处理 (仅适用于单例bean)

登记善后处理需要同时满足两个条件,分别是:

bean的生命周期是单例。

bean实现了可销毁接口(DisposableBean) 或者 配置了销毁方法(destroy-method="...") 或者 容器中存在销毁敏感bean后处理器(DestructionAwareBeanPostProcessor)。

如果以上两个条件满足,那么Spring会为对bean对象创建一个DisposableBeanAdapter对象,这个对象主要持有以下几点信息,

bean对象是否实现了可销毁接口(DisposableBean) 。

如果bean配置了销毁方法(destroy-method="..."),则获取销毁方法名称及方法对象。

从当前容器的bean后处理器集合中,过滤出所有销毁敏感bean后处理器(DestructionAwareBeanPostProcessor),作为列表赋值给成员变量。

被创建的DisposableBeanAdapter对象,会被存储到DefaultSingletonBeanRegistry类的成员变量Map<String, Object> disposableBeans中,其中key是bean's Id。当Spring容器被关闭时(即ConfigurableApplicationContext#close()方法被调用),会调用存储在disposableBeans中的所有DisposableBeanAdapter对象的destroy()方法,执行善后处理。

对于web应用ConfigurableApplicationContext#close()方法是在ContextLoaderListener监听器中被自动触发的,但是对于桌面应用,如果希望“善后处理”得到执行需要手动调用ConfigurableApplicationContext#registerShutdownHook()方法,当java虚拟机被关闭时,会回调注册的方法。

四. 注册单例Bean(仅适用于单例bean)

把单例bean对象置入DefaultSingletonBeanRegistry类的成员变量singletonObjects 。

/**
* 单例对象缓存(key:bean名称;value:单例bean对象)
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();


把单例bean对象的Id置入DefaultSingletonBeanRegistry类的成员变量registeredSingletons。

/**
* 已注册的单例bean名称集合
*/
private final Set<String> registeredSingletons = new LinkedHashSet<String>(16);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息