Bean 的生命周期
我们知道 Web 容器中的 Servlet 拥有明确的生命周期,Spring 容器中的 Bean 也拥有相似的生命周期。Bean 生命周期由多个特定的生命阶段组成。每个生命阶段都开出了一扇门,允许外界借由此门对 Bean 进行控制。
在 Spring 中,可以从两个方面定义 Bean 的生命周期 : 第一个层面是 Bean 的作用范围;第二个层面是实例化 Bean 时所经历的一系列阶段。下面分别对 BeanFactory 和 ApplicationContext 中 Bean 的生命周期进行分析。
BeanFactory 中 Bean 的生命周期
生命周期图解如下 :
-
当调用者调用了 getBean(beanName) 向容器请求某一个 Bean 时,如果容器注册了 InstantiationAwareBeanPostProcessor 接口,则在实例化 Bean 之前,将调用接口的 postProcessBeforeInstantiation()方法 。
-
根据配置情况调用 Bean 构造参数或工厂方法实例化 Bean 。
-
如果容器注册了 InstantiationAwareBeanPostProcessor 接口,那么在实例化 Bean 之后,调用该接口的 postProcessAfterInstantiation()方法。
-
如果Bean 配置了属性信息,那么容器在这一步将配置值设置到 Bean 对应的属性值中,不过在设置这个属性之前先调用 InstantiationAwareBeanPostProcessor 接口的 postProcessPropertyValues() 方法。
-
调用 Bean 的属性设置方法设置属性值。
-
如果 Bean 实现了 BeanNameAware 接口,则调用 setBeanName(String name) 接口方法 ,将配置文件中该 Bean 对应的名称设置到 Bean 中。
-
如果 Bean 实现了 BeanFactoryAware 接口,则调用接口的 setBeanFactory(BeanFactory beanFactory) 方法, 将 BeanFactory 设置到 Bean 中。
-
如果 BeanFactory 装配了 BeanPostProcessor 后处理器,则调用 Object postProcessBeforeInitialization(Object bean, String beanName)方法 ,参数 bean 为当前正在处理的 Bean , 而 beanName 为当前 Bean 的配置名,返回对象为加工处理后的 Bean 。开发者可以使用该方法对 Bean 进行特殊的处理,甚至改变 Bean 的行为。 BeanPostProcessor 在 Spring 框架中占有重要的地位,为容器提供对 Bean 进行后续加工处理的切入点, 为 Spring 容器所提供的各种功能 (如 AOP ,动态代理等) 都通过 BeanPostProcessor 实施。
-
如果 Bean 实现了InitializingBean 接口,则将调用接口的 afterPropertiesSet() 方法 。
-
如果在 <bean> 中通过了 init-method 属性定义了初始化方法 ,则将执行该方法。
-
BeanPostProcessor 后处理器定义了两个:其一是 postProcessBeforeInitialization 在第八步调用 ,其二是 postProcessAfterInitialization 方法在此时调用 , 容器再次获得对 Bean 进行加工处理的机会。
-
如果在<bean> 中指定 bean 的作用范围为 scope= “prototype” ,则将 Bean 返回给调用者,调用者负责 Bean 后续生命的管理,Spring 不再管理这个 Bean 的生命周期。如果将左右范围设置为 scope = “singleton” ,则将 Bean 放入 Spring IoC 容器的缓存池中,并将 Bean 的引用返回给调用者 , Spring 继续对这些 Bean 进行后续的生命管理。
-
对于 scope = “singleton” 的 Bean (默认情况) ,当容器关闭时,将触发 Spring 对 Bean 后续生命周期的管理工作。如果 Bean 实现了 DisposableBean 接口,将调用该接口的 destroy() 方法 。可以在此编写释放资源、记录日志等操作。
-
对于 scope = “singleton” 的 Bean,如果通过 <bean> 的 destroy-method 指定了 Bean 的销毁方法,那么 Spring 将执行 Bean 的这个方法,完成 Bean 资源的释放等操作。
Bean 的完整生命周期从 Spring 容器实例化 Bean 开始,直到最终销毁 Bean 。其中经过了很多的方法调用,可以将这些方法大体划分为四类 :
-
Bean 自身的方法 :如调用 Bean 构造函数实例化 Bean ,调用 Setter 方法设置 Bean 的属性值及通过 <bean> 的 init-method 和 destroy-method 所指定的方法。
-
Bean 级生命周期接口的方法 :如 BeanNameAware 、BeanFactoryAware、InitializingBean 和 DisposableBean,这些接口由 Bean 类直接实现。
-
容器级生命接口方法 ,如由 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 两个接口实现的,一般称他们的实现类为“后处理器”。 后处理器接口一般不由 Bean 本身实现,他们独立于 Bean ,实现列以容器附加装置的形式注册到 Spring 容器中,并通过接口反射为 Spring 容器扫描识别。 当 Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用。所以这些后处理器的影响是全局性的。当然,可以合理的编写后处理器,让其仅对感兴趣的 Bean 进行加工处理。
-
工厂后期处理接口方法 : 包括 AspectJWeavingEnabler 、CustomAutowireConfigurer、ConfigurationClassPostProcessor 等方法。工厂后处理器也是容器级的,在应用上下文装配配置文件后立即调用。
Bean 级生命周期接口和容器级生命周期接口是个性和共性辩证统一思想的实现,前者解决 Bean 个性化处理的问题,而后者解决容器中某些 Bean 共性化处理的问题。
Spring 容器可以注册多个后置处理器,只要他们同时实现 Ordered 接口,容器将按特定的顺序依次调用这些后处理器。InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 的子接口, Spring 为其提供了一个适配器类 InstantiationAwareBeanPostProcessorAdapter ,一般情况下,可以方便的扩展该适配器覆盖感兴趣的方法以定义实现类。
通过 <bean> 的 init-method 和 destroy-method 属性配置方式可以为 Bean 指定初始化和销毁的方法,采用这种方式对 Bean 的生命周期控制效果和通过 InitializingBean 和DisposableBean 接口所达到的效果是完全相同的。采用前者的配置方式可以使 Bean 不需要和特定的 Spring 接口绑定,达到了框架解耦的目的 。此外,Spring 还拥有一个Bean 后置处理器InitDestroyAnnotationBeanPostProcessor ,它负责对标注了 @PostConstruct 、@PreDestroy 的 Bean 进行处理,在 Bean 初始化后和销毁前执行相应的逻辑。因此可以通过 InitDestroyAnnotationBeanPostProcessor 达到以上两种方式相同的效果(如果在 ApplicationContext 中,则已经默认装配了该处理器)。
对于 BeanFactoryAware 和 BeanNameAware 接口,前者让 Bean 感知容器 (BeanFactory 实例),而后者让 Bean 获得配置文件中对应的配置名称。一般情况下,用户几乎不需要关心这两个接口。
ApplicationContext 中 Bean 的生命周期
Bean 在 ApplicationContext 中的生命周期和在 BeanFactory 中的生命周期类似,不同的是,如果 Bean 实现了ApplicationContextAware 接口,则会增加一个调用该接口的步骤 setApplicationContext(ApplicationContext applicationContext) 。
此外,如果在配置文件中声明了工厂后处理器接口 BeanFactoryPostProcessor 的实现类,则应用上下文在加载配置文件后、初始化示例之前将调用这些 BeanFactoryPostProcessor 对配置信息进行加工处理。Spring 框架提供了多个工厂后处理器,如 CustomEditorConfigurer 、PropertyPlaceholderConfigurer 等。如果在配置文件中定义了多个工厂后处理器,那么最好让它们实现 Ordered 接口,以便 Spring 以确定顺序调用它们。工厂后处理器是容器级的,仅在应用上下文初始化时调用一次,其目的是完成一些配置文件的加工处理工作。
ApplicationContext 和 BeanFactory 另一个最大的不同之处在于 : 前者会利用 Java 反射机制自动识别出配置文件中定义的 BeanPostProcessor、InstantiationAwareBeanPostProcessor 和 BeanFactoryPostProcessor,并将它们自动注册到应用上下文中,而后者需要在代码中手工调用 setBeanPostProcessor() 方法进行注册。这是为什么在应用开发时普遍使用 ApplicationContext 而很少使用 BeanFactory 的原因之一。
在 ApplicationContext 中,只需要在配置文件中通过 <bean> 定义工厂后处理器和 Bean 后处理器,它们就会以预期方式执行。其生命周期图如下 :