Spring可以管理singleton作用域Bean的生命周期,Spring可以精确的知道该Bean何时被创建、何时被初始化完成、容器何时准备销毁该Bean实列。
对于prototype作用域的Bean,Spring容器仅负责创建,当容器创建了Bean实列之后,Bean实列完全交给客户端代码管理,容器不再跟踪其生命周期。
对于singleton作用域的Bean,Spring容器知道Bean何时实列化结束、何时销毁。Spring可以管理Bean在实列化结束之后和销毁之前的行为。管理Bean的生命周期行为主要有如下两个时机:
一、注入依赖关系后
Spring提供两种方式在Bean注入依赖关系后执行特定行为;
第一:在xml中配置<bean>时,为其配置init-method属性,该属性指定Bean全部依赖关系设置结束后,自动执行该属性指定的方法;
第二:让Bean类实现InitalizingBean接口,该接口提供public void afterPropertiesSet() throws Exception方法。
<!--使用init-method指定Bean注入后执行方法-->
<bean id="init" class="com.custle.spring.Init" init-method="init"/>
package com.custle.spring;
import org.springframework.beans.factory.InitializingBean;
/**
* Created by admin on 2018/3/1.
*/
public class Init implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("正在执行初始化方法 afterPropertiesSet()");
}
public void init(){
System.out.println("正在使用init-method属性指定初始化方法 init()");
}
}
测试程序:
package com.custle.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by admin on 2018/3/1.
*/
public class BeanFactory {
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
act.getBean("init");
}
}
程序输出:
正在执行初始化方法 afterPropertiesSet()
正在使用init-method属性指定初始化方法 init()
可以看见,当同时使用这两种方式初始化方法时,先执行InitializingBean接口中定义的方法,然后执行init-method属性指定的方法。使用InitializingBean接口的方式代码耦合性较高。
二、Bean销毁之前的行为
与定制初始化行为相似,Spring也提供了两种方式定制Bean销毁之前的特定行为,这两种方式如下:
第一:在xml中配置<bean>时使用destory-method属性;
第二:实现DisposableBean接口;
<!--使用destory-method指定Bean销毁前执行方法-->
<bean id="destory" class="com.custle.spring.Destory" destroy-method="close"/>
package com.custle.spring;
import org.springframework.beans.factory.DisposableBean;
/**
* Created by admin on 2018/3/1.
*/
public class Destory implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("正在通过实现DisposableBean接口执行Bean销毁前的destroy()方法");
}
public void close(){
System.out.println("正在通过destory-method执行Bean销毁前的close()方法");
}
}
测试程序:
package com.custle.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by admin on 2018/3/1.
*/
public class BeanFactory {
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
act.getBean("destory");
}
}
控制台输出:
正在使用init-method属性指定初始化方法 init()
可以看见当同时使用这两种方式执行Bean销毁前行为时,只有通过init-method属性配置的方式生效了。这是为什么呢?单列Bean的生命周期随着Spring容器的关闭而销毁,如果在一个非WEB应用环境下,为了让Spring容器优雅的关闭,并调用singleton Bean上相应的析构回调方法,则需要在JVM中注册一个关闭钩子,这样就可以保证Spring容器被恰当关闭。
使用如下测试程序:
package com.custle.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by admin on 2018/3/1.
*/
public class BeanFactory {
public static void main(String[] args) {
AbstractApplicationContext act = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
act.getBean("destory");
act.registerShutdownHook();
}
}
控制台输出:
正在通过实现DisposableBean接口执行Bean销毁前的destroy()方法
正在通过destory-method执行Bean销毁前的close()方法
可以看见当这两种方式同时执行时,通过实现DisposableBean接口执行销毁Bean前的行为优先级更高。
除此之外,如果容器中很多Bean都需要指定特定的生命周期行为,则可以在<beans>中设置default-init-method属性和default-destory-method属性,它们的作用和init-method、destory-method属性类似,只不过它们是对该<beans>下所有的bean都生效。
当Bean实现了ApplicationContextAware接口、BeanNameAware接口之后,Spring容器会在该Bean初始化完成之后--也就是调用init-method属性所指定的方法(如果有)之后,再回调setApplicationConetext(ApplicationContext applicationConext)、setBeanName(String name)方法。