spring之bean的生命周期
上篇文章中,详细介绍了spring中bean的scope,scope既是bean在spring容器中的存在方式,如prototype和singleton,且也带了一些存在周期的属性,如 session和request等。spring中 bean从实例化,到依赖注入、再到初始化、到最后消亡,有和完整的生命周期。它和scope一起构成bean完整的生命周期。本篇文章主要简单的描述下bean生命周期中的
上篇文章中,详细介绍了spring中bean的scope,scope既是bean在spring容器中的存在方式,如prototype和singleton,且也带了一些存在周期的属性,如 session和request等。spring中 bean从实例化,到依赖注入、再到初始化、到最后消亡,有和完整的生命周期。它和scope一起构成bean完整的生命周期。本篇文章主要简单的描述下bean生命周期中的初始化方法(init())和消亡前(ondestroy(),以后称之为析构)的方法。本文主要讨论scope为prototype和singleton的bean,且由于prototype的bean在返回给客户端后,spring不在由spring进行管理,所以其销毁前的方法不会执行。
spring中bean的生命周期简单的如下图所示:
我们可以在生命周期函数中加入自己的一些定制化处理,比如说在初始化阶段,加载相关的资源,启动线程等,在析构阶段释放资源,关闭线程。需要牢记一点,初始化函数是在所有的依赖已经注入后才开始执行的。
生命周期回调
其中中bean的初始化和消亡前主要由以下几种方式:
1.Spring的接口InitializingBean和DisposableBean。示例如下:
/**
* InitializingBean 接口从名字可以看出此方法在 bean的属性被spring赋值之后执行,但是和spring的接口耦合在了一起
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(this+" i am afterPropertiesSet");
}
/* *
* DisposableBean 接口定义的
*/
@Override
public void destroy() throws Exception {
System.out.println(this+" i am destroy");
}
2.采用元数据配置,即在bean的定义中配置,如 init-method 和 destroy-method属性,直接定义相关方法,另外在根标签<beans>可以配置default-init-method 和default-destroy-method 配置默认的 方法,如果<bean>中有定义,则覆盖默认的定义:
<bean id="user0" class="com.test.service.UserServiceIml" init-method="testInit" destroy-method="testBeforeDesstroy">
<property name="userDao" ref="userDao"></property>
</bean>
/**
* @Description: 采用元数据配置,在xml中配置
* @param
* @return void
*/
public void testInit(){
System.out.println(this+" i am testInit");
}
/**
* @Description: 采用元数据配置,在xml中配置
* @param
* @return void
*/
public void testBeforeDesstroy(){
System.out.println(this+" i am testBeforeDesstroy");
}
3.采用JSR注解
/**
* @Description: 采用jsr注解
* @param
* @return void
*/
@PostConstruct
public void testPostConstruct(){
System.out.println(this+" i am testPostConstruct");
}
/**
* @Description: 采用JSR的注解
* @param
* @return void
*/
@PreDestroy
public void testPreDesstroy(){
System.out.println(this+" i am testPreDesstroy");
}
混合机制
以上有三种回调函数实现的方式,他们可以单独使用,也可以混合使用,混合使用的时候,他们的顺序如下:
对于初始化函数:
1. @PostConstruct 注解的方法
2. InitializingBean接口定义的回调afterPropertiesSet()
3. Bean配置中自定义的初始化函数
对于析构则与上相同:
1. @PreDestroy注解的方法
2. DisposableBean接口定义的回调destroy()
3. Bean配置中自定义析构函数
详细的测试见后面。
startUp和shutDown回调
有时候我们可能需要一些组件的功能随着spring容器的启动而启动(如新开启一个线程来进行监听),容器的销毁而销毁。为此spring提供了一个接口,从方法名字很容易看到方法的作用:
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
当启动的时候,由于组件之间的依赖,启动的顺序是相当重要的。depends-on属性可以决定多个lifecycle的实现的顺序,但是有时候依赖是未知的。为此spring定义可一个新的接口,SmartLifecycle:
public interface Phased {
int getPhase();
}
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
isAutoStartup决定是随着容器的启动自启动,Phased接口定义的方法则决定了启动顺序,其返回值越小启动越早,越大启动越晚。如果一个Lifecycle未实现Phased接口,则默认其值为0.
Stop方法可以异步的执行析构函数,spring默认会为每一个Phase等待30秒钟。这个时间是可以配置的。
测试
在非web环境下,要使析构函数执行,需要执行AbstractApplicationContext的registerShutdownHook()方法,见本文的示例:
本测试准备说明以下:
1. 混合生命周期回调的执行顺序
2. LifeCycle也可以看做为周期,其中start方法在初始化函数执行后被调用,stop方法在析构函数执行前被调用。Prototype 不会被调用start和 stop方法
3. Depend-on决定bean加载的顺序
4. <bean>定义的回调会覆盖<beans>定义的默认的回调。
代码
以下是测试程序,本程序依赖Spring之容器和配置初识这篇文章中的代码,并对其稍加改动:
代码结构如下:
首先是allbean.xml配置文件:
<!--使JSR注解生效 -->
<bean id="postsss" class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
<!-- 也可以使用这个配置 使JSR生效 <context:annotation-config/> -->
<!-- 改变在容器关闭阶段,smartlifecycle 每个阶段 等待的时间 -->
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="3000"/>
</bean>
<import resource="com/test/dao/dao.xml"/>
<import resource="com/test/service/service.xml"/>
然后是service.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-init-method="init"
default-destroy-method="close"
>
<!-- 配置自己的初始化和析构,覆盖默认配置 -->
<bean id="user0" class="com.test.service.UserServiceIml" init-method="testInit" destroy-method="testBeforeDesstroy">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 采用默认配置的初始化和析构 -->
<bean id="user1" class="com.test.service.UserServiceIml">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 配置scope为 prototype,测试只执行初始化函数,不执行析构 -->
<bean id="user2" class="com.test.service.UserServiceIml" scope="prototype">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 以下测试 depend-on -->
<bean id="t1" class="com.test.service.Test1" depends-on="t2">
</bean>
<bean id="t2" class="com.test.service.Test2" >
</bean>
</beans>
然后是UserServiceIml实现了相关的接口,使用了jsr注解和实现了bean中配置的初始化和析构函数:
package com.test.service;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.SmartLifecycle;
import com.test.bo.User;
import com.test.dao.UserDao;
/**
*实现类,有个字段引用了UserDao接口,其具体的业务逻辑调用 {@link UserDao#getUser()}实现
*
*且有一个set方法,此set方法由spring 容器注入使用,如果没有回报错,
*这是spring容器依赖注入的一种方法--setter注入
*/
public class UserServiceIml implements UserService,InitializingBean,DisposableBean,SmartLifecycle{
private volatile boolean isRunning = false;
private UserDao userDao;
@Override
public List<User> getUser() {
return userDao.getUser();
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
System.out.println(this+" i am setMethod");
}
/**
* InitializingBean 接口从名字可以看出此方法在 bean的属性被spring赋值之后执行,但是和spring的接口耦合在了一起
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(this+" i am afterPropertiesSet");
}
/* *
* DisposableBean 接口定义的
*/
@Override
public void destroy() throws Exception {
System.out.println(this+" i am destroy");
}
/**
* @Description: 采用jsr注解
* @param
* @return void
*/
@PostConstruct
public void testPostConstruct(){
System.out.println(this+" i am testPostConstruct");
}
/**
* @Description: 采用JSR的注解
* @param
* @return void
*/
@PreDestroy
public void testPreDesstroy(){
System.out.println(this+" i am testPreDesstroy");
}
/**
* @Description: 采用元数据配置,在xml中配置
* @param
* @return void
*/
public void testInit(){
System.out.println(this+" i am testInit");
}
/**
* @Description: 采用元数据配置,在xml中配置
* @param
* @return void
*/
public void testBeforeDesstroy(){
System.out.println(this+" i am testBeforeDesstroy");
}
public void init(){
System.out.println(this+" i am init");
}
public void close(){
System.out.println(this+" i am close");
}
@Override
public boolean isRunning() {
returnisRunning;
}
@Override
public void start() {
System.out.println(this+"spring容器启动啦");
isRunning = true;
}
/**
*
*/
@Override
public void stop() {
System.out.println(this+"spring容器关闭啦");
isRunning = false;
}
@Override
public int getPhase() {
return 0;
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public void stop(Runnable arg0) {
arg0.run();
isRunning = false;
System.out.println(this+" this is stop");
}
}
主程序:
public class TestMain {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("allbean.xml");
context.registerShutdownHook();
UserService userService0 = context.getBean("user0", UserService.class);
System.out.println(userService0.getUser());
System.out.println("--------------user1采用默认的初始化函数--------------");
//
UserService userService1 = context.getBean("user1", UserService.class);
//
System.out.println(userService1.getUser());
//
UserService userService2 = context.getBean("user2", UserService.class);
//
System.out.println(userService2.getUser());
}
}
测试结果
以上测试结果就不分析了。需要注意的的上面的测试结果第一行由于截图的关系空缺了。
结束语
Bean的生命周期spring是采用beanpostProcessor(称之为spring扩展点)来进行管理和扩展的,spring定义了很多内置的beanpostProcessor,它们的一些回调在bean的实例化(这里指返回客户端调用前,而不是new)过程中被调用,且如果bean实现了一些aware接口(如ApplicationContextAware 和 beanNameAwre
),这些接口的回调也会进入到生命周期中,这里暂且不讨论。见文章:http://developer.51cto.com/art/201104/255961.htm。而且,spring广泛采用代理机制,需要注意的是 生命周期函数运行在代理创建之前。本文的测试代码下载:本文代码完整下载
更多推荐
所有评论(0)