0
点赞
收藏
分享

微信扫一扫

[Spring Framework]bean的生命周期以及控制


文章目录

  • ​​bean的生命周期控制(配置文件法)​​
  • ​​容器的关闭​​
  • ​​bean的生命周期控制(实现接口法)​​
  • ​​总结​​

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 Framework]bean的生命周期以及控制_生命周期

我们发现销毁方法并没有执行,这是为什么呢?

Spring的IOC容器是运行在JVM中,运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行,main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了,所以没有调用对应的destroy方法。

容器的关闭

如果我们想要销毁方法生效,那么我们就要在jvm关闭之前就把IOC容器进行关闭,而这里关闭IOC容器有两种方式:

  • close关闭容器
  • 注册钩子关闭容器

首先我们说说如何使用close关闭容器。要想使用close方法,那么得先有close方法:

[Spring Framework]bean的生命周期以及控制_java_02


close方法是从ConfigurableApplicationContext接口之后才开始有的,也就是说如果你写成如下是调用不了close方法的:

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

如上是一个注意点,好在我们的代码是没有这种问题的:

[Spring Framework]bean的生命周期以及控制_后端_03


然后调用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();

}
}

结果:

[Spring Framework]bean的生命周期以及控制_jvm_04

然后我们再注册钩子关闭容器,

  • 在容器未关闭之前,提前设置好回调函数,让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();
}
}

结果:

[Spring Framework]bean的生命周期以及控制_生命周期_05

这两种关闭方法的区别在于: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>

执行结果:

[Spring Framework]bean的生命周期以及控制_jvm_06


还有一个注意点:

对于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();
}
}

然后我们再执行,结果如下:

[Spring Framework]bean的生命周期以及控制_java_07

总结

(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()方法


举报

相关推荐

0 条评论