容器中Bean的生命周期

Spring可以管理singleton作用域Bean的生命周期,可以精确地知道该Bean何时被创建、何时被初始化完成、容器何时准备注销该Bean实例。

管理Bean的生命周期行为主要有如下两个时机:

 > 注入依赖关系之后

 > 即将销毁Bean之前


对于prototype作用域的Bean,Spring容器仅仅负责创建,当容器创建了Bean实例之后,Bean实例完全交给客户端代码管理,容器不再跟踪其生命周期。


1、依赖关系注入之后的行为

Spring提供两种方式在Bean全部属性设置成功后执行特定行为:

 > 使用init-method属性

 > 实现InitializingBean接口

第一种方式:使用init-method属性指定某个方法应在Bean全部依赖关系设置结束后自动执行。该方法无需将代码与Spring接口耦合在一起,代码污染小。

第二种方式也可以达到同样的效果,就是让Bean类实现InitializingBean接口,该接口提供一个方法:void afterPropertiesSet() throws Exception。


package LifecycleOfBean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import DependencyInjection.Axe;
import DependencyInjection.Person;

public class Chinese implements Person ,InitializingBean
{

	private Axe axe;
	
	public Chinese(){
		System.out.println("Spring实例化主调bean:Chinese实例...");
	}

	public void setAxe(Axe axe) {
		System.out.println("Spring执行依赖注入...");
		this.axe = axe;
	}
	
	@Override
	public void useAxe() {
		// TODO Auto-generated method stub	
		System.out.println(axe.chop());
	}

	//测试用初始化方法
	public void init(){
		System.out.println("正在执行初始化方法init.");
	}
	//实现InitializingBean接口必须实现的方法
	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("正在执行初始化方法afterPropertiesSet..");
	}

}
上面的程序定义了一个普通的init()方法,实际上这个方法的方法名是任意的,并不一定是init()方法,Spring也不会对这个init()方法进行任何特别的处理。只是接下来会在配置文件中用 init-method 属性指定该方法时一个“生命周期”。

增加 init-method="init" 来指定init() 方法应在Bean的全部属性设置结束后自动执行,如果它不实现InitializingBean接口,上面的Chinese类没有实现任何Spring接口,只是增加一个普通的init() 方法,它依然是一个普通的Java文件,没有代码污染。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://www.springframework.org/schema/beans"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"
>
	<bean id="steelAxe" class="DependencyInjection.SteelAxe"/>

	<bean id="chineseLC" class="LifecycleOfBean.Chinese"
	 	init-method="init">
		<property name="axe" ref="steelAxe"/>
	</bean>
	
</beans>

package LifecycleOfBean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import DependencyInjection.Person;

public class Test {

	public static void main(String[] args) {
		
		ApplicationContext ctx =
				new ClassPathXmlApplicationContext("bean.xml");
		
		Person p = ctx.getBean("chineseLC",Person.class);
		p.useAxe();	
	}

}



对于实现InitializingBean接口的Bean,无须使用init-method 属性来指定初始化方法,配置该Bean实例与配置普通Bean实例完全一样,Spring容器会自动检测Bean实例是否实现了特定生命周期接口,并由此决定是否需要执行生命周期方法。

如果某个Bean类实现InitializingBean 接口,当该Bean的所有依赖关系被设置完成后,Spring容器会自动调用该Bean实例的afterPropertiesSet() 方法。其执行结果与采用 init-method 属性指定生命周期方法几乎一样。但实现InitializingBean 接口污染了代码,是侵入式设计,因此不推荐使用。

如果既采用 init-method 属性指定初始化方法,又实现InitializingBean 接口来指定初始化方法,容器会执行两个初始化方法:先执行InitializingBean 接口中定义的方法,然后执行init-method属性指定的方法。


2、Bean销毁之前的行为

与定制初始化行为相似,Spring也提供两种方法定制Bean实例销毁之前的特定行为,这两种方式如下:

 > 使用destroy-method属性

 > 实现DisposableBean接口

第一种方式:使用destroy-method属性指定某个方法应在Bean销毁之前被自动执行。使用这种方法,不需要将代码与Spring接口耦合在一起,代码污染小。

第二种方式也可以达到同样的效果,就是让Bean类实现DisposableBean接口,该接口提供一个方法:void destroy() throws Exception。


package LifecycleOfBean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import DependencyInjection.Axe;
import DependencyInjection.Person;

public class Chinese implements Person ,DisposableBean
{

	private Axe axe;
	
	public Chinese(){
		System.out.println("Spring实例化主调bean:Chinese实例...");
	}

	public void setAxe(Axe axe) {
		System.out.println("Spring执行依赖注入...");
		this.axe = axe;
	}
	
	@Override
	public void useAxe() {
		// TODO Auto-generated method stub	
		System.out.println(axe.chop());
	}

	public void close(){
		System.out.println("正在执行销毁前方法close.");
	}
	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("正在执行销毁前方法destroy..");
	}
}

上面的程序定义了一个普通的close()方法,实际上这个方法的方法名是任意的,并不一定是close()方法,Spring也不会对这个close()方法进行任何特别的处理。只是接下来会在配置文件中用 destroy-method 属性指定该方法时一个“生命周期”。

增加 destroy-method="close" 来指定close() 方法应在Bean实例销毁之前自动执行,如果它不实现DisposableBean接口,上面的Chinese类没有实现任何Spring接口,只是增加一个普通的close() 方法,它依然是一个普通的Java文件,没有代码污染。


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://www.springframework.org/schema/beans"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"
>
	<bean id="chineseLC" class="LifecycleOfBean.Chinese"
	 	destroy-method="close">
		<property name="axe" ref="steelAxe"/>
	</bean>
</beans>


singleton作用域的Bean通常会随容器的关闭而销毁,但问题是:ApplicationContext容器在什么时候关闭呢?在基于Web的ApplicationContext实现中,系统已经提供了相应的代码保证关闭Web应用时恰当地关闭Spring容器。

如果处于一个非Web应用的环境下,为了让Spring容器优雅地关闭,并调用singleton Bean上的相应析构回调方法,则需要再JVM里注册一个关闭钩子(shutdown hook),这样就可保证Spring容器被恰当关闭,且自动执行singleton Bean实例的析构回调方法。

为了注册关闭钩子,只需要调用AbstractApplicationContext中提供的registerShutdownHook() 方法既可。

package LifecycleOfBean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import DependencyInjection.Person;

public class Test {

	public static void main(String[] args) {
		
		ApplicationContext ctx =
				new ClassPathXmlApplicationContext("bean.xml");
		
		Person p = ctx.getBean("chineseLC",Person.class);
		p.useAxe();
		
		//为Spring容器注册关闭钩子
		((AbstractApplicationContext) ctx).registerShutdownHook();
	}

}



如果某个Bean类实现DisposableBean 接口,在Bean被销毁之前,Spring容器会自动调用该Bean实例的destroy() 方法。其执行结果与采用destroy-method 属性指定生命周期方法几乎一样。但实现DisposableBean 接口污染了代码,是侵入式设计,因此不推荐使用。

对于实现DisposableBean接口的Bean,无须使用destroy-method 属性来指定销毁之前的方法,配置该Bean实例与配置普通Bean实例完全一样,Spring容器会自动检测Bean实例是否实现了特定生命周期接口,并由此决定是否需要执行生命周期方法。

如果既采用 destroy-method 属性指定销毁之前的方法,又采用实现DisposableBean 接口来指定销毁之前的方法,容器会执行两个初始化方法:先执行DisposableBean 接口中定义的方法,然后执行destroy-method属性指定的方法。


除此之外,如果容器中有很多Bean都需要指定特定的生命周期行为,则可以利用<beans.../>元素的 default-init-method 属性和 default-destroy-method 属性,这两个属性的作用类似于<bean.../>元素的 init-method 属性和 destroy-method 属性,关键是 default-init-method 属性和 default-destroy-method 属性是属于<beans.../>元素的,它们将使容器中所有Bean生效。


Spring容器中Bean实例完整的生命周期行为:

开始 → 创建实例 → 注入依赖关系 → 调用afterPropertiesSet → 调用init-method 方法 → 对外提供服务 → 调用destroy → 调用destroy-method 方法→ Bean实例被销毁


需要指出的是,当Bean实现了ApplicationContextAware接口、BeanNameAware接口之后,Spring容器会在该Bean初始化完成之后——也就是调用init-method 属性所指定的方法(如果有)之后,再来回调setApplicationContext(ApplicationContext applicationContext)、setBeanName(String name) 方法。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值