这个章节官方文档写的很乱,这些是自己验证后所写,如有错误,欢迎指出
生命周期回调
我们可以实现InitializingBean和DisposableBean接口。容器会调用前者的afterPropertiesSet()方法,调用后者的destory()方法,以允许在初始化和销毁bean时执行某些操作,也可以使用@PostConstruct和@PreDestory注解来实现生命周期回调,通过BeanPostProcessor实现类,Spring可以找到任何回调接口的实现类并调用适当的方法。
初始化回调
建议使用注解@PostConstruct,可以防止应用与spring容器耦合,对于xml配置,可以通过下述方式防止代码耦合:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
public void init() {
// do some initialization work
}
}
上述方式等效于:
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean {
public void afterPropertiesSet() {
// do some initialization work
}
}
销毁回调
建议使用注解@PreDestory,对于XML配置,采用下述方法防止代码耦合:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
上述方式等效于:
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
destory-method可以指定为一个特殊值——inferred,此时spring会自动匹配指定bean中的close或是shutdown方法。
默认的初始化和销毁方法
通过指定<beans/>的default-init-method、default-destroy-method属性,可以让spring在每次创建完一个对象后或是销毁一个对向前调用相应的方法(如果存在),不必每次在<bean>中指明init-method或是destroy-method的值,我们可以通过在<bean>中指明init-method或是destroy-method的值来覆盖default-init-method、default-destroy-method的值,当所有依赖都已经注入bean后,spring才会执行init-method和default-init-method指定的函数,当一个bean完全创建完毕后,AOP拦截链和代理才会开始执行(配置了AOP的情况),将拦截器应用到init-method指定的方法是不明智的,此时会将bean的创建与拦截器结合起来
结合生命周期的机制
在spring2.5中,有三种选择来控制bean生命周期的行为:
1、InitializingBean、DisposableBean
2、init-method、destroy-method的值
3、@PostConstruct和@PreDestory
我们可以糅合这几种机制
使用不同的方法为同一bean配置多个初始化生命周期,调用顺序如下:
1、@PostConstruct
2、InitializingBean 中的afterPropertiesSet()
3、init-method的值
使用不同的方法为同一bean配置多个销毁生命周期,调用顺序如下:
1、@PreDestory
2、DisposableBean中的destory()
3、destroy-method的值
启动和关闭回调
当SpringIOC容器启动后或是关闭前,我们想启动或是停止一些后台进程,此时可以使用启动和关闭回调
Lifecycle接口:
public interface Lifecycle {
//接收到start信号时,若isRunning返回为false,则调用
void start();
//接收到stop信号时,若isRunning返回true,则调用
void stop();
//返回的boolean值将决定容器接收到启动或是停止命令时是运行start还是stop
boolean isRunning();
}
在容器刷新阶段(关闭并重启BeanFactory),不会接收到stop信号,在容器自启动(不是显式调用start方法)阶段,不会接收到start信号,如果想对Bean提供更加精确的控制,可以考虑继承实现SmartLifecycle,容器关闭时,若isRunning()返回true,将会调用所有实现了Lifecycle的bean的stop方法,接着调用销毁方法,如果是刷新(刷新时会销毁已经存在BeanFactory),此时只会调用bean的销毁方法,spring通过LifecycleProcessor的实现类来处理生命周期回调:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
如果我们想进一步控制bean的行为,例如控制bean初始化的顺序,可以考虑使用SmartLifecycle:
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
//一定要使用callback.run(),否则DefaultLifecycleProcessor认为bean的stop方法一直没有结束(即使已经结束),超过30s后,可以通过下列方式更改等待时间
/*<bean id="lifecycleProcessor"
*class="org.springframework.context.support.DefaultLifecycleProcessor">
* <!-- timeout value in milliseconds -->
* <property name="timeoutPerShutdownPhase" value="10000"/>
*</bean>
*/
//DefaultLifecycleProcessor才会自己调用callback.run,与主程序异步执行
void stop(Runnable callback);
}
public interface Phased {
//返回一个Phase,作为调用start和stop方法的顺序
int getPhase();
}
SmartLifecycle继承了Lifecycle,但是Lifecycle的stop方法将不在有意义,当isRunning()返回true时,将调用void stop(Runnable callback),启动时,Phase(即优先值)越小,越早调用start()方法,越晚调用stop()方法,如果不继承SmartLifecycle接口,只继承了Lifecycle接口,Phase默认为0.,我们使用上述接口定义了自己的bean的生命周期后,Phase相同的Bean一起启动和关闭,如果bean与bean之间有依赖关系,则忽略Phase的值
容器刷新或是启动时,DefaultLifecycleProcessor将检查每个SmartLifecycle对象的isAutoStartup()方法返回的布尔值,如果为true,并且isRunning返回为false,将直接调用其start方法,isRunning指在接收到start信号时,是否调用start方法,isAutoStartup()的作用在于设定容器自启动时,DefaultLifecycleProcessor是否传递start信号给本类
在基于web的ApplicationContext实现中,已有相应的实现来处理关闭web应用时恰当地关闭Spring IoC容器。
如果你正在一个非web应用的环境下使用Spring IoC容器,想让容器优雅的关闭,并调用singleton的bean相应stop回调方法,你需要在JVM里注册一个“关闭钩子”(shutdown hook):
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
}
猜测registerShutdownHook()会收集所有的stop回调方法(isRunning返回为true),并将其注册为线程,在JVM关闭时,会执行这些线程