Java 杂谈细说Spring我爱编程

细说Spring——IoC详解(Bean的生命周期)

2018-05-22  本文已影响20人  Jivanmoon

我们在细说Spring——IoC详解(一)细说Spring——IoC详解(二)中了解了容器启动阶段所做的事情,还有在容器启动阶段我们可以做的扩展,同时笼统的了解了一下容器是怎么创造出一个对象之后,我们接下来就要进入Bean的实例化阶段,同时学习一下在Bean的实例化阶段我们可以做哪些扩展。
首先我们先来看一个图:

这里写图片描述
这个图是《Spring揭秘》中的一个图,我们接下来就可以对照这个图来了解Bean的实例化过程。
1、Bean的实例化和属性设置

当我们完成了容器的启动阶段后,对于BeanFactory来说,并不会马上实例化相应的bean定义。我们知道,容器现在仅仅拥有所有对象的BeanDefinition来保存实例化阶段将要用的必要信息。只有当请求方通过BeanFactorygetBean()方法来请求某个对象实例的时候,才有可能触发Bean实例化阶段的活动BeanFactorygetBean()法可以被客户端对象显式调用,也可以在容器内部隐式地被调用。隐式调用有如下两种情况:

容器在实现Bean的实例化的时候,采用“策略模式(Strategy Pattern)"来决定采用何种方式初始化bean实例。通常,可以通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或者动态生成其子类。

这里就涉及到了一些AOP的知识,我们只需要知道在容器中并不是直接通过new的方式来添加对象,而是通过AOP实现机制,创造了一个目标对象的代理对象就可以了,代理对象可以简单理解为目标对象的子类,他要么和目标对象有相同的功能,要么能力比目标对象强大,AOP我会在以后进行详细讲解。

但是容器也并不是直接就创造了一个代理对象,他还把这个代理对象包装了一下,他把代理对象包装成了一个BeanWrapper

BeanWrapper定义继承了org.springframework.beans.PropertyAccessor接口,可以以统一的方式对对象属性进行访问;BeanWrapper定义同时又直接或者间接继承了PropertyEditorRegistryTypeConverter接口。不知你是否还记得CustomEditorConfigurer?当把各种PropertyEditor注册给容器时,知道后面谁用到这些PropertyEditor吗?对,就是BeanWrapper!在第一步构造完成对象之后,Spring会根据对象实例构造一个BeanWrapperImpl实例,然后将之前CustomEditorConfigurer注册的PropertyEditor复制一份给BeanWrapperImpl实例(这就是BeanWrapper同时又是PropertyEditorRegistry的原因)。然后我们就可以通过BeanWrapper来为对象设置属性了。

2、Aware接口

到这里图中的前两个过程就已经走完了,接下来,容器会检查当前对象实例是否实现了一系列的以Aware命名结尾的接口定义。如果是,则将这些Aware接口定义中规定的依赖注入给当前对象实例。我们可以看一看这些Aware对象到底规定了什么依赖,对于BeanFactory来说,Aware接口有一下几个:

对于ApplicationContext类型的容器,也存在几个Aware相关接口。如下:

在了解了这些Aware接口的功能后,我们可能会想容器是如何实现将Aware接口中规定的依赖注入到已经生成的对象中的呢?这里就要引出我们在容器实例化阶段的扩展点了,那就是BeanPostProcessor

3、BeanPostProcessor

BeanFactoryPostProcessor通常会处理容器内所有符合条件的BeanDefinition类似,BeanPostProcessor会处理容器内所有符合条件的实例化后的对象实例。

我们已经知道BeanFactoryPostProcessor是在容器启动阶段,对象还未创建之前对创建对象的信息就是BeanDefinition进行了修改,那么BeanPostProcessor是如何对一个已经生成的对象进行扩展的呢,这里当然就要用到AOP了,看来,Spring中的IoCAOP真是“你中有我,我中有你”啊。

我们ApplicationContext对应的那些Aware接口实际上就是通过BeanPostProcessor的方式进行处理的。当ApplicationContext中每个对象的实例化过程走到BeanPostProcessor前置处理这一步时,ApplicationContext容器会检测到之前注册到容器的ApplicationContextAwareProcessor这个BeanPostProcessor的实现类,然后就会调用其postProcessBeforeInitialization()方法,检查并设置Aware相关依赖。

至于如何将BeanPostProcessor注册到容器中,BeanFactory需要手动的写代码注入,而ApplicationContext可以通过配置文件的方式注入,下面是代码实现:

BeanFactory

ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(...));
beanFactory.addBeanPostProcessor(new PasswordDecodePostProcessor()); 
ApplicationContext

<beans>
    <bean id="passwordDecodePostProcessor" class="package.name.PasswordDecodePostProcessor">
     <!--如果需要,注入必要的依赖-->
     </bean> 
</beans> 
4、init-method

通俗的将,init-method可以指定我们在容器中的获得的对象在执行任何方法前,先执行那个方法。比如我们在做任何事情前必须要先洗手,那么我可以把洗手定义为init-method,那么我们在做吃饭,睡觉,玩游戏,写代码。。。。之前都会去洗手。下面演示一下如何定义init-method

<bean id="tradeDateCalculator" class="FXTradeDateCalculator" ➥
 init-method="setupHolidays"> 

这里只需要保证FXTradeDateCalculator类中有一个setupHolidays方法就可以了。

5、destory-method

init-method对应,destory-method定义的是在所有这个对象被销毁前,需要做的方法。
这里就不具体的举例子了,如果想了解更多关于destory-method的相关知识,可以参考:Spring中的destroy-method方法

上一篇下一篇

猜你喜欢

热点阅读