Spring不仅提供了基本的IOC功能,借助于BeanFactory以及其它组件,我们还可以使用其它一些更高级的功能。但是需要注意的是,使用这些高级功能,将不可避免的使得我们的工程依赖于Spring。这些高级功能大致包括:管理bean的生命周期,让bean感知Spring(Spring aware),使用方法注入,使用FactoryBean,使用PropertyEditor以及了解Spring的ApplicationContext
有时候,我们需要在bean的生命周期中的某些阶段做一些相应的操作(类似于Servlet和EJB),像其它IOC容器一样,Spring也提供了管理bean生命周期的功能。两个主要的阶段是:
post-initialization(bean初始化之后)和pre-destruction(bean销毁之前).
post-initialization是指在Spring完成了bean的所有依赖注入以及相应的检测之后,
pre-destruction是指在Spring销毁bean之前。
post-initialization和pre-destruction只能应用于sigleton模式的bean,因为非sigleton的bean的生命周期并不由Spring控制(它们是由JVM控制的)。
Spring提供了两种机制来实现bean生命周期的管理:基于接口的和基于指定方法的。
使用基于接口的机制,我们需要实现Spring的相关接口,然后,Spring会使用回调机制在指定的阶段调用接口中定义的方法,从而实现bean生命周期的管理。而使用基于指定方法的机制,我们需要在BeanFactory的配置中指定相应的方法名称,Spring会使用Java的反射机制在指定的阶段调用我们指定的方法,从而实现bean生命周期的管理。
选择哪种机制取决于我们的工程的需要。基于接口的机制要求我们实现Spring的接口,这会带来对Spring的依赖,但是当我们定义了很多相同类型的bean时,使用基于接口的机制可以免去我们为每个bean定义指定相应方法的麻烦。基于指定方法的机制则可以让我们避免对Spring的依赖,这在当我们使用第三方的类库(因此,我们无法修改其代码来实现Spring的接口)时是非常有用的。
以post-initialization为例:
使用基于接口的机制,我们需要实现Spring的InitializingBean接口的afterPropertiesSet方法
public class SimpleBeanWithInterface implements InitializingBean {
...
public void afterPropertiesSet() throws Exception {
...
}
...
}
<beans>
<bean id="simpleBean1"
class="com.apress.prospring.ch5.lifecycle.SimpleBeanWithInterface">
...
</bean>
</beans>
使用基于指定方法的机制,我们只需在BeanFactory的配置中指定相应的方法名称
<beans>
<bean id="simpleBean1"
class="com.apress.prospring.ch5.lifecycle.SimpleBean"
init-method="init">
...
</bean>
</beans>
SimpleBean中包含对应的init方法
public class SimpleBean {
...
public void init() {
...
}
...
}
需要注意的是,init方法必须不包含任何参数,尽管我们可以为init方法指定任意的返回值,但Spring会忽略它,因此最好的做法是在init方法中抛出异常来表明初始化失败了。
我们也可以同时使用这两种机制,这时,Spring会先调用InitializingBean接口的afterPropertiesSet方法,再调用我们自己指定的init方法。
相对的,pre-destruction使用DisposableBean接口的destroy方法和bean标签的destroy-method属性
相对于依赖查找(Dependency Lookup),依赖注入(Dependency Injection)最大的卖点就是容器的无关性,但是有时候,我们确实需要和容器进行一些交互,例如访问BeanFactory或者是获得bean的名称等。
为了获得bean的名称,我们需要实现Spring的BeanNameAware接口,BeanNameAware只有一个方法,void setBeanName(String name),只要我们的bean实现了BeanNameAware接口,Spring就会在bean配置结束,其它生命周期相关的回调函数(initialization或者 destroy)调用之前,回调该方法置入bean的名称。
类似的,为了访问beanFactory,我们需要实现Spring的BeanFactoryAware接口的
void setBeanFactory(BeanFactory factory)方法。