7.9.2 Bean销毁之前的行为
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实例完整的生命周期行为: