生命周期:从创建到销毁的完整过程
Bean生命周期:Bean从创建到销毁的整体过程
Bean生命周期控制:在Bean创建后到销毁前做的事情
先写一个简单的Bean控制Dao
<bean id="bookDao" class="com.cacb.dao.impl.BookDaoImpl"/>
在bookdao中写一个save方法来调用
(impl文件内容)
@Override
public void save(){
System.out.println("Dao saving!");
}
基本配置完成,下面进入可视化部分
既然生命周期的关键就在于Bean的创建和销毁
那我们不妨给其设置init()和destory()两个方法,在Bean创建和销毁的时候调用这两个方法来证明这两个事件的发生
public void init(){
System.out.println("bookdao init!");
}
public void destory(){
System.out.println("bookdao destory!");
}
当然,仅仅写出这两个方法是无法让虚拟机知道该在什么时候调用这两个方法的,所以我们需要修改一下Bean的配置
<bean id="bookDao" class="com.cacb.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
意思简单明了,记不住全拼多按几下TAB即可,不多做赘述
但是 我们会发现输出结果只有:
destory方法的输出结果呢?
究其原因,我们的程序自始至终是运行在JAVA虚拟机上的
当虚拟机启动时,IoC容器加载配置一并启动
测试程序从容器中拿取到了Bean
执行了我们调用的save方法,
至此程序执行完毕,虚拟机退出
并没有给其机会来销毁Bean。
所以,想要看到Bean的销毁,我们需要需要使用一定的手段
方法有二
? ? ? ? 先看我们的测试程序:
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
}
怎么操作?,在save后调用容器的close()方法来关闭容器
ctx.close();
但我们发现ApplicationContext接口中不具备close方法,查询ApplicationContext接口的继承关系之后,我们会发现close()方法实在ApplicationContext接口的一个继承接口中书写的,所以我们干脆修改代码,直接将ctx定义为ClassPathXmlApplicationContext类型,就可以直接调用close()方法了
修改后代码:
(非常好从IDEA复制代码,使我的IDEA继每日一崩MAVEN之后又卡死了一次)
(很好,电脑也死机了一次)
public class Demo_BeanLifCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
ctx.close();
}
}
再运行测试程序,得到结果如下
可以看到destory方法确实被调用
但是,使用close方法来关闭容器是较为暴力的方法,所以引入下一方法
ctx.registerShutdownHook();
给ctx容器设置一个关闭钩子,告诉虚拟机需要在关闭之前关闭管道
运行结果如下:
?
可以看到,两种方法所实现的最终效果是一致的,但是其二者还是有去别的
????????close方法较为暴力,必须在程序完成所有有关bean的操作后再调用,否则书写在close后的有关内容不会被运行
????????而关闭钩子可以在管道构建好以后的任何位置书写,虚拟机会在运行完程序的所有代码后再关闭管道
那么在实际应用中应该选用哪种方法呢?
实际上在实际应用中我们都是在开发web程序,关闭管道交由tomcat完成,这两种方法我们都是用不上的,在此只作为学习Bean生命周期的知识点出现!
在这种方法中,要实现Bean生命周期的控制,我们需要继承Spring提供的两个接口
InitializingBean和 DisposableBean
继承这两个接口后,我们还要覆写接口中的两个方法:
@Override
public void destroy() throws Exception {
}
@Override
public void afterPropertiesSet() throws Exception {
}
我们用serviceimpl来dao来区分两种控制方法的实现
public class BookServiceSImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
@Override
public void save(){
System.out.println("Service saving!");
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void destroy() throws Exception {
System.out.println("service distroy!");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("service init!");
}
}
dao代码见前一种控制方法
调用测试程序,
public class Demo_BeanLifCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
//ctx.close();
ctx.registerShutdownHook();
}
}
获得结果:
可以看到,虽然我们没有调用sevice,但是由于doa和service存于同一个管道中,service也会被加载,所以也能看到service的创建和销毁