`

Spring知识整理(七)—— IoC容器扩展(下)

阅读更多

Bean的生命周期

IoC容器的启动分为两个阶段,容器启动阶段和Bean实例化阶段。容器启动阶段上一篇已经介绍过了,下面说下Bean实例化阶段。对于BeanFactory,对象默认是延迟加载的,而ApplicationContext启动之后会实例化所有的bean定义,只不过ApplicationContext在启动后会调用注册到该容器的所有beangetBean()方法。不妨根据Bean的生命周期做下理解:


 
1.       实例化bean对象

容器内部采用“策略模式(Strategy Pattern)”来决定采用何种方式初始化bean实例。通常,可以通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或者动态生成其子类。InstantiationStrategy是实例化策略的抽象接口,它有以下两个子类:

SimpleInstantiationStrategy:通过反射实例化,不支持注入。

CglibSubclassingInstantiationStrategy:继承于SimpleInstantiationStrategy,反射实例化,并通过CGLIB的动态字节码生成功能,可以动态生成某个类的子类,进而实现了方法注入。

容器根据bean定义的BeanDefintion取得实例化信息,结合CglibSubclassingInstantiationStrategy以及bean定义的类型,返回实例化完成的以BeanWrapper进行包裹的对象实例。

 

2.       设置对象属性

BeanWrapper继承于PropertyAccessor接口有一实现类BeanWrapperImpl,功能包括设置或者获取bean的相应属性值。同时又直接或者间接继承了PropertyEditorRegistryTypeConverter接口。在介绍CustomEditorConfigurer时,我们提到了PropertyEditor,而注册到容器的PropertyEditor就是供BeanWrapper使用的。

在第一步构造完成对象之后,Spring会根据对象实例构造一个BeanWrapperImpl实例,然后将之前CustomEditorConfigurer注册的PropertyEditor复制一份给BeanWrapperImpl实例(这就是BeanWrapper同时又是PropertyEditorRegistry的原因)。这样BeanWrapper就可以根据给出的PropertyEditor来转换类型、设置对象属性值。

 

3.       检查Aware接口并设置依赖

当对象属性和依赖设置完成之后,Spring容器会检查当前对象实例是否实现了一系列的以Aware命名结尾的接口定义。如果是,则将这些Aware接口定义中规定的依赖注入到当前对象。

Spring定义了如下几个Aware接口:

BeanNameAware:将beanName设置到当前对象实例。

BeanClassLoaderAware:将对应加载当前beanClassloader注入当前对象实例。

BeanFactoryAwareBeanFactory容器会将自身设置到当前对象实例。

(以下为ApplicationContext容器会进一步检查的接口,都是将ApplicationContext自身注入到当前对象实例)

ResourceLoaderAware

ApplicationEventPublisherAware

MessageSourceAware

ApplicationContextAware

 

4.       BeanPostProcessor

在容器的启动阶段,我们提到过BeanFactoryPostProcessor的概念。BeanPostProcessor容易与BeanFactoryPostProcessor混淆,只要记住这两个概念分别存在于不同阶段就能很好的区分。

BeanPostProcessor接口定义了两个方法,分别是postProcessBeforeInitialization()postProcessAfterInitialization(),这两个方法分别对应BeanPostProcessor的前置处理和后置处理阶段,两个方法的参数都是bean的实例和beanName,这样我们就可以对对象进行任何操作了。

通常比较常见的使用BeanPostProcessor的场景,是处理标记接口实现类,或者为当前对象提供代理实现。ApplicationContext容器定义的Aware接口的处理和Spring中注解的处理就是由BeanPostProcessor完成的。我们可以看下处理Aware的相关代码: 

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof ResourceLoaderAware) { 
        ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    }
    if (bean instanceof ApplicationEventPublisherAware) {
        ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher (this.applicationContext);
    } 
    if (bean instanceof MessageSourceAware) { 
        ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    }
    if (bean instanceof ApplicationContextAware) { 
        ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    }
    return bean; 
}

 

SpringAOP同样使用BeanPostProcessor来为对象生成相应的代理对象,如BeanNameAutoProxyCreator等,这个会在介绍AOP的时候详细说明。

 

当然,我们可以定义自己的BeanPostProcessor,做法就是实现BeanPostProcessor接口,然后将自定义的BeanPostProcessor注册到容器中:

ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(...));

beanFactory.addBeanPostProcessor(new PasswordDecodePostProcessor());

对于于ApplicationContext,会自动识别并加载,所以只要在配置文件中配置下即可:

<bean id="passwordDecodePostProcessor" class="package.name.PasswordDecodePostProcessor">

<!--如果需要,注入必要的依赖-->

</bean>

 

1.       InitializingBeaninit-method

InitializingBean是容器内部广泛使用的一个对象生

命周期标识接口,其定义如下:

public interface InitializingBean {

void afterPropertiesSet() throws Exception;

}

该接口定义很简单,其作用在于,在调用过“BeanPostProcessor的前置处理”之后,会接着检测当前对象是否实现了InitializingBean接口,如果是,则会调用其afterPropertiesSet()方法进一步调整对象的状态。比如,在有些情况下,某个业务对象实例化完成后,还不能处于可以使用状态。这个时候就可以让该业务对象实现该接口,并在方法afterPropertiesSet()中完成对该业务对象的后续处理。

虽然该接口在Spring容器内部广泛使用,但如果真的让我们的业务对象实现这个接口,则显得Spring容器比较具有侵入性。所以,Spring还提供了另一种方式,在XML配置的时候,使用<bean>init-method属性:

<bean id="myCar" class=" com.zrabbit.production.Car" init-method="initCar">

 

至此,容器使用前的初始化工作已经全部完成。

 

2.       DisposableBeandestroy-method

当一个singleton类型的bean实例使用后,容器将检查其是否实现了DisposableBean接口。或者是否通过<bean>destroy-method属性指定了自定义的对象销毁方法。如果是,就会为该实例注册一个用于对象销毁的回调(Callback),以便在这些singleton类型的对象实例销毁之前,执行销毁逻辑。

InitializingBeaninit-method用于对象的自定义初始化相对应,DisposableBeandestroy-method为对象提供了执行自定义销毁逻辑的机会:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

 

不过,这些自定义的销毁逻辑,在对象实例初始化完成并注册了相关的回调方法之后,并不会马上执行。回调方法注册后,返回的对象实例即处于使用状态,只有该对象实例不再被使用的时候,才会执行相关的自定义销毁逻辑,此时通常也就是Spring容器关闭的时候。但Spring容器在关闭之前,不会聪明到自动调用这些回调方法。所以,需要我们告知容器,在哪个时间点来执行对象的自定义销毁方法。

对于BeanFactory容器来说,我们需要调用ConfigurableBeanFactory提供的destroySingletons()方法销毁容器中管理的所有singleton类型的对象实例。对于ApplicationContext容器来说,我们可以调用AbstractApplicationContext提供的registerShutdownHook()方法。

 

public static void main(String[] args) {
    BasicConfigurator.configure();
    BeanFactory container = new XmlBeanFactory(new ClassPathResource("..."));
    BusinessObject bean = (BusinessObject)container.getBean("...");
    bean.doSth();
    ((ConfigurableListableBeanFactory)container).destroySingletons();
    // 应用程序退出,容器关闭
}

 

public static void main(String[] args) {
    BasicConfigurator.configure();
    BeanFactory container = new ClassPathXmlApplicationContext("..."); 
    ((AbstractApplicationContext)container).registerShutdownHook();
    BusinessObject bean = (BusinessObject)container.getBean("...");
    bean.doSth();
    // 应用程序退出,容器关闭
}

  

 

  • 大小: 43.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics