Spring学习手册(5)——bean作用域我们学习了Spring为我们提供的bean的几类声明周期声明,我们重点学习了singleton
和prototype
两种声明。本文我们将学习如何与IOC容器的bean生命周期管理进行交互。
一、实现方式
当我们需要在bean初始化和销毁时执行特定的动作时,Spring为我们提供了两个不同的方式来实现:
- bean继承
InitializingBean
和�DisposableBean
接口。接口InitializingBean
的afterPropertiesSet()
会在属性设置方法调用完成后调用;接口DisposableBean
的destroy()
方法会在bean销毁时(超出作用域)执行; - 使用XML配置的方式:其中
标签的init-method
属性可制定该bean的初始化方法,destroy-method
属性可指定bean的销毁方法。效果与集成接口方式一致。
为了简化学习成本并且减少代码与Spring框架的耦合,这里我们主要讲解演示XML配置方式的使用。
Tip : 除以上方法外,Spring还提供了注解的方式来声明初始化方法和销毁方法,如:
@PostConstruct
和@PreDestroy
,这里也不做进一步讲述。
二、初始化方法和销毁方法配制
当我们需要bean在初始化完成后执行相关动作时,我们可以使用Spring提供的XML配置方式来指定代码类的相应方法为初始化方法。样式如下:
public class ExampleBean {
public void init() {
// 执行相关的初始化操作
}
}
如上所示,在XML配置文件中我们使用init-method
属性指定该bean的public void init()
方法为初始化方法。该方法要求返回值为void
且无参,除此之外,名字可任意更改,只需要保证bean所指定的类中包含此方法。
同样,我们可以如下简单的配置销毁方法:
public class ExampleBean {
public void cleanup() {
// bean销毁时,做一些清理工作
}
}
和初始化方式相似,我们使用destroy-method
方法指定销毁时的清理方法,上面的例子中指向public void cleanup()
,该方法同样也是返回值为void
且无参,其中方法名可任意更改。
三、更近一步
当我们需要为大量的bean
配置初始化方法和销毁清理方法时,Spring也为我们提供了更高效的方式:在beans
标签里使用default-init-method
和default-destroy-method
属性,同时我们需要让我们的所有bean
只需要定义相同的初始化方法签名和销毁清理方法签名。
代码样式如下:
public class ExampleBean {
public void init(){
//执行相关的初始化操作
}
public void cleanup() {
// bean销毁时,做一些清理工作
}
}
public class ExampleBean2 {
public void init(){
//执行相关的初始化操作
}
public void cleanup() {
// bean销毁时,做一些清理工作
}
}
如上配置方式,我们对ExampleBean
和ExampleBean2
完成了初始化操作方法和销毁清理方法,其中特别重要的时所有bean
的初始化方法和销毁方法必须一致:一般我们使用public void init()
方法签名来定义初始化方法。
Tip: 当我们需要为某一个
bean
设置特殊的初始化方法或销毁清理方法是,我们只需要在具体的bean
定义标签里使用init-method
属性指定,它会覆盖全局设置。
四、代码示例
示例代码构造了主要使用三个类来进行演示,主要展示一下功能:
类名 | 展示功能 |
---|---|
LifecycleExample1 | 展示各方法的调用顺序 |
LifecycleExample2 | 演示全局配置方式效果 |
LifecycleExample3 | 演示特殊bean配置覆盖全局配置 |
代码构造如下:
LifecycleExample1.java
public class LifecycleExample1 {
private int num;
public LifecycleExample1() {
System.out.println("LifecycleExample1 constructed!");
}
public void setNum(int num) {
this.num = num;
System.out.println("LifecycleExample1 setNum method called!");
}
public void init(){
System.out.println("LifecycleExample1 init method called!");
}
public void cleanup(){
System.out.println("LifecycleExample1 cleanup method called!");
}
}
LifecycleExample2.java
public class LifecycleExample2 {
public void init(){
System.out.println("LifecycleExample2 init method called!");
}
public void cleanup(){
System.out.println("LifecycleExample2 cleanup method called!");
}
}
LifecycleExample3.java
public class LifecycleExample3 {
public void anotherInit(){
System.out.println("LifecycleExample3 anotherInit method called1");
}
public void init(){
System.out.println("LifecycleExample3 init method called!");
}
}
以上代码简单就不做过多赘述。
配置方式如下:
请特别注意default-init-method
、default-destroy-method
属性的使用以及lifecycleExample3
配置中init-method
属性的使用。
Application.java
为了使Spring能调用我们的配置的销毁清理方法,我们需要IOC容器注册一个JVM关闭的钩子(hook),如下所示:
public class Application {
public static void main(String[] args){
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
applicationContext.registerShutdownHook();
}
}
运行代码控制台显示信息如下:
LifecycleExample1 constructed!
LifecycleExample1 setNum method called!
LifecycleExample1 init method called!
LifecycleExample2 init method called!
LifecycleExample3 anotherInit method called1
LifecycleExample2 cleanup method called!
LifecycleExample1 cleanup method called!
通过输出信息我们可以总结:
- 初始化方法会在seter方法调用完成后被IOC容器调用;
- 当配置全局
default-init-method
或default-destroy-method
后,该配置文件下的所有bean如果有该方法会在合适时机被调用; - 当使用
init-method
或destroy-method
对全局配置进行覆盖时,即使该bean
有全局配置的方法也不会被调用,而是只调用最新配置的方法。
五、总结
本文我们讲述了如何在bean完成初始化或销毁时执行指定的动作。通过该方式我们就可以灵活的进行一些操作:系统启动时预加载缓存,提高执行效率;系统启动时初始化数据库连接等......
本文源代码下载