7.9.2 Bean销毁之前的行为
与定制初始化行为相似, Spring
也提供两种方式定制Bean
实例销毁之前的特定行为,这两种方式如下。
- 使用
destroy-method
属性。 - 实现
DisposableBean
接口。
第一种方式:使用destroy-method
属性指定某个方法在Bean
销毁之前被自动执行。使用这种方式不需要将代码与Spring
的接口耦合在一起,代码污染小。
第二种方式:就是实现Disposable Bean
接口,重写该接口内的方法destroy()
方法,该方法定义为:void destroy() throws Exception
。
程序示例
项目结构
1 | E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\lifecycle-destroy |
Chinese.java
下面的示例程序让Chinese
类既包括一个普通方法,但在配置时将该普通方法指定为生命周期方法;也让该Chinese
类实现DisposableBean
接口,因此也包含一个destroy()
生命周期方法。该Chinese
类的代码如下。
1 | package org.crazyit.app.service.impl; |
上面程序中的粗体字代码定义了一个普通的close()
方法,实际上这个方法的方法名是任意的,并不定是close()
,Spring
也不会对这个close()
方法进行任何特别的处理。只是配置文件使用destroy-method
属性指定该方法是一个”生命周期方法”。
增加destroy-method="close"
来指定close
方法应在Bean
实例销毁之前自动执行,如果它不实现DisposableBean
接口,上面的Chinese
类没有实现任何Spring
的接口,只是增加一个普通的closed
方法,它依然是一个普通的Java
文件,没有代码污染。
上面程序中的destroy()
方法是实现DisposableBean
接口必须实现的方法。
beans.xml
在配置文件中增加destroy-method="close"
,指定close
方法应该在Bean
实例销毁之前自动被调用。
配置文件代码如下。
1 |
|
配置该Bean
与配置普通Bean
没有任何区别, Spring
可以自动检测容器中的DisposableBean
,在销毁Bean
实例之前, Spring
容器会自动调用该Bean
实例的destroy()
方法。singleton
作用域的Bean
通常会随容器的关闭而销毁,但问题是:ApplicationContext
容器在什么时候关闭呢?
Web应用关闭时会自动关闭Spring容器
在基于Web
的ApplicationContext
实现中,系统已经提供了相应的代码保证关闭Web
应用时恰当地关闭Spring
容器。
在非Web环境如何关闭Spring容器
如果处于一个非Web
应用的环境下,为了让Spring
容器优雅地关闭,并调用singleton Bean
上的相应析构回调方法,则需要在JVM
里注册一个关闭钩子( shutdown hook)
,这样就可保证Spring
容器被恰当关闭,且自动执行singleton Bean
实例的析构回调方法。
如何注册关闭钩子来关闭Spring容器
为了注册关闭钩子,只需要调用在AbstractApplicationContext
中提供的registerShutdownHook()
方法即可。
BeanTest.java
看如下主程序
1 | package lee; |
上面程序的最后一行粗体字代码为Spring
容器注册了一个关闭钩子,程序将会在退出JVM
之前优雅地关闭Spring
容器,并保证关闭Spring
容器之前调用singleton Bean
实例的析构回调方法。
运行结果
运行上面的程序,将可以看到程序退出执行输出如下两行:
1 | ... |
通过上面的执行结果可以看出,在Spring
容器关闭之前,注入之后,程序先调用destroy()
方法进行回收资源,再调用close()
方法进行回收资源。
不推荐实现DisposableBean接口方式
如果某个Bean
类实现了DisposableBean
接口,在Bean
实例被销毁之前, Spring
容器会自动调用该Bean
实例的destroy()
方法。其执行结果与采用destroy-method
属性指定生命周期方法几乎一样。但实现DisposableBean
接口污染了代码,是侵入式设计,因此不推荐采用。
对于实现Disposable Bean
接口的Bean
,无须使用destroy-method
属性来指定销毁之前的方法,配置该Bean
实例与配置普通Bean
实例完全一样, Spring
容器会自动检测Bean
实例是否实现了特定生命周期接口,并由此决定是否需要执行生命周期方法。
先执行DisposableBean接口方法再执行destroy-method属性指定的方法
如果既采用destroy-method
属性指定销毁之前的方法,又采用实现DisposableBean
接来指定销毁之前的方法, Spring
容器会执行两个方法:先执行DisposableBean
接口中定义的方法,然后执行destroy-method
属性指定的方法
在beans元素上为所有bean指定生命周期行为
除此之外,如果容器中的很多Bean
都需要指定特定的生命周期行为,则可以利用<beans>
元素的default-init-method
属性和default-destroy-method
属性,这两个属性的作用类似于<bean>
元素的init-method
和destroy-method
属性的作用,区别是default-init-method
属性和default-destroy- method
属性是属于<beans>
元素的,它们将使容器中的所有Bean
生效。
1 | <beans default-init-method="init"> |
上面配置片段中的代码指定了default-init-method="init"
,这意味着只要Spring
容器中的某个Bean
实例具有init()
方法, Sprin
就会在该Bean
的所有依赖关系被设置之后,自动调用该Bean
实例的init()
方法。
Spring容器中Bean实例完整的生命周期行为
图7.12显示了Spring
容器中Bean
实例完整的生命周期行为:
原文链接: 7.9.2 Bean销毁之前的行为