2.5 IoC容器的其他相关特性的设计与实现

2.5.1 ApplicationContext和Bean的初始化及销毁

ApplicationContext的初始化以及销毁过程如下图所示:

在使用应用上下文时的一些准备工作在prepareBeanFactory()中实现,它为容器配置了ClassLoader、PropertyEditor和BeanPostProcessor等,为容器的启动做好必要的准备工作。关闭也是同样需要完成一系列工作,这些工作在doClose()中完成,先发出容器关闭的信号,然后将Bean逐个关闭,最后关闭容器自身。

以上过程是容器的初始化和销毁,这与Bean的初始化和销毁不一样。开发中常常要执行比如数据库连接、打开网络连接等特定且固定的初始化工作,结束服务时也有固定的销毁工作,为了方便,Spring IoC容器提供相关功能,能让应用定制Bean的初始化和销毁过程。在分析Bean的初始化和销毁过程前,先看IoC容器中Bean的生命周期:

(1) Bean实例的创建。

(2) 为Bean实例设置属性。

(3) 调用Bean的初始化方法。

(4) 应用可以通过IoC容器使用Bean。

(5) 当容器关闭时,调用Bean的销毁方法。

Bean的初始化方法调用是在initializeBean方法中实现的,在调用之前先调用一系列的aware接口实现,把相关的BeanName、BeanClassLoader以及BeanFactory注入到Bean中,再调用invokeInitMethods,在invokeInitMethods方法里面还会启动afterPropertiesSet过程。最后判断Bean是否配置有initMethod,如果有,则通过invokeCustomInitMethod方法来直接调用,最终完成Bean的初始化。

Bean的销毁过程是先对postProcessBeforeDestruction进行调用,然后调用Bean的destroy方法,最后是对Bean的自定义销毁方法的调用。

2.5.2 lazy-init属性和预实例化

如前面的博客所述,在IoC容器的初始化过程中,主要是对BeanDefinition的定位、载入、解析和注册,此时依赖注入没有发生,依赖注入发生在应用第一次向容器所要Bean时(getBean)。而有一种例外就是用户通过设置Bean的lazy-init属性来控制预实例化的过程,这个预实例化在初始化容器时就完成了依赖注入。用户通过在BeanDefinition中设置lazy-init属性来控制依赖注入的触发时间,这种方式对容器的初始化性能有一定影响,但却能提高应用第一次取得Bean的性能,因为在应用第一次取Bean之前依赖注入就已经完成了。

回头看上下文的初始化过程,是由refresh()来启动初始化的,而refresh包含了对lazy-init属性的处理。Refresh中的finishBeanFactoryInitialization方法中,封装了对lazy-init属性的处理,实际处理是在DefaultListableBeanFactory这个基本容器的preInstantiateSingletons方法中完成的,该方法对单件Bean完成预实例化,如果需要预实例化就直接在这里采用getBean去触发依赖注入,与正常依赖注入的触发相比,只是时间和场合的不同。

2.5.3 FactoryBean的实现

先说一下FactoryBean和BeanFactory的区别:

FactoryBean:是一个Java Bean,但是它是一个能生产对象的工厂Bean,它的实现和工厂模式及修饰器模式很像。如果把bean比作是人,那么FactoryBean可以算是一个女人,首先它本身也是一个人,并且它能够生产人(不是很恰当的比喻,但是能说明问题)。

BeanFactory:这就是一个Factory,是一个IOC容器或者叫对象工厂,它里面存着很多的bean。还用上面那个例子:如果bean是人,那么BeanFactory可以理解成学校,学校里面很多人,学校管理这么多的人。

无论是直接取单例的bean,还是创建单例、多例、自定义生命周期的bean,都会经过bean = getObjectForBeanInstance这个方法,getObjectForBeanInstance里面又调用了getObjectFromFactoryBean,这里返回的已经是作为工厂的FactoryBean生产的产品,而不是FactoryBean本身,如果希望得到它本身,只需要加上&符号即可。这种机制可以提供一个很好的封装机制,比如封装Poxy、JDNI、RMI等。FactoryBean的核心就在于通过getObject方法可以获取的是它所生产的对象,所以我们在Proxy创建代理对象的时候就比较方便。还有一些bean,如果通过配置的方式,会显得比较麻烦和复杂,那么这时候适当的采用编码方式在某些场合下还是挺不错的。

猜你喜欢

转载自my.oschina.net/u/3342874/blog/1821229
2.5