@[TOC]
bean的生命周期控制(配置文件法)
bean的生命周期就是bean对象从创建到销毁的整体过程。
我们在bean的生命周期中可以干一些事情(也就是对他的生命周期进行一些控制),例如创建之后(比如用来初始化需要用到资源),销毁之前(比如用来释放用到的资源)。
接下来我们进行尝试:
首先项目背景:
有一个实现了BookDao接口的是实现类BookDaoImpl:
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
我们把它放到IOC容器中:
<bean id="bookDao" name="bookBookDao" class="impl.BookDaoImpl"/>
接下来我们就以这个实现类BookDaoImpl为例子:
首先我们在实现类BookDaoImpl中编写两个方法,分别对应着初始化方法、销毁方法:
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
注意这两个方法不能有返回值,不要有参数!
然后我们在Spring的配置文件中对他们进行配置,是他们真正的成为生命周期的控制方法:
<bean id="bookDao" name="bookBookDao" class="impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
- 用
init-method
来配置初始化方法 - 用
destroy-method
来配置销毁方法
这样就完成了,接下来我们运行程序:
public class App3 {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
结果为:
==我们发现销毁方法并没有执行,这是为什么呢?==
Spring的IOC容器是运行在JVM中,运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行,main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了,所以没有调用对应的destroy方法。
容器的关闭
如果我们想要销毁方法生效,那么我们就要在jvm关闭之前就把IOC容器进行关闭,而这里关闭IOC容器有两种方式:
- close关闭容器
- 注册钩子关闭容器
首先我们说说如何使用close关闭容器。要想使用close方法,那么得先有close方法:
close方法是从ConfigurableApplicationContext接口之后才开始有的,也就是说如果你写成如下是调用不了close方法的:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
如上是一个注意点,好在我们的代码是没有这种问题的:
然后调用close方法即可:
public class App3 {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
ctx.close();
}
}
结果:
然后我们再注册钩子关闭容器,
- 在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器
调用ctx的registerShutdownHook()方法
ctx.registerShutdownHook();
注意:registerShutdownHook在ApplicationContext中也没有
public class App3 {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
// ctx.close();
ctx.registerShutdownHook();
}
}
结果:
这两种关闭方法的区别在于:==close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。==
bean的生命周期控制(实现接口法)
分析上面的实现过程,会发现添加初始化和销毁方法,即需要编码也需要配置,实现起来步骤比较多也比较乱。
Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置init-method
和destroy-method
我们接下来进行试验:
添加项目背景:
现在有一个实现了BookService接口的BookServiceImpl类,它依赖于BookDao:
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
我们以他为例子,首先实现两个接口InitializingBean
, DisposableBean
并实现接口中的两个方法afterPropertiesSet
和destroy
:
public class BookServiceImpl implements BookService, DisposableBean, InitializingBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
在配置文件中,我们可以不使用那两个配置项:
<bean id="bookDao" name="bookBookDao" class="impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
<bean id="bookService" class="impl.BookServiceImpl" scope="prototype">
<property name="bookDao" ref="bookBookDao"></property>
</bean>
执行结果:
还有一个注意点:
对于InitializingBean接口中的afterPropertiesSet方法,翻译过来为属性设置之后
。对于BookServiceImpl来说,bookDao是它的一个属性。setBookDao方法是Spring的IOC容器为其注入属性的方法。setBookDao应该在afterPropertiesSet之前执行。==推广一下初始化方法会在类中属性设置之后执行。==
我们实验一下:
在setBookDao中添加一个打印语句:
public class BookServiceImpl implements BookService, DisposableBean, InitializingBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
System.out.println("set property....");
this.bookDao = bookDao;
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
然后我们再执行,结果如下:
总结
(1)关于Spring中对bean生命周期控制提供了两种方式:
- 在配置文件中的bean标签中添加
init-method
和destroy-method
属性 - 类实现
InitializingBean
与DisposableBean
接口,这种方式了解下即可。
(2)对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:
初始化容器
- 1.创建对象(内存分配)
- 2.执行构造方法
- 3.执行属性注入(set操作)
- ==4.执行bean初始化方法==
使用bean
- 1.执行业务操作
关闭/销毁容器
- ==1.执行bean销毁方法==
(3)关闭容器的两种方式:
ConfigurableApplicationContext是ApplicationContext的子类
- close()方法
- registerShutdownHook()方法