- 实现spring框架的IntializingBean和DisposableBean接口前者调用afterPropertiesset()方法,后者调用destory方法
- 自定义初始化和摧毁方法通过在bean上配置init-method,detroy-method实现
- 使用JSR-250 @PostConstruct和PreDestory注释在方法上实现初始化和摧毁方法
//student类
public class Student implements InitializingBean,DisposableBean{
private String name;
public Student(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void init() {
System.out.println("init---");
}
public void destory() {
System.out.println("destory---");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("属性设置之后进行回掉...");
}
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("自定义之前进行删除...");
}
@PostConstruct
public void inita() {
System.out.println("注释初始化");
}
@PreDestroy
public void desa() {
System.out.println("注释销毁");
}
}
//配置类
@Configuration
public class Config {
@Bean(initMethod="init",destroyMethod="destory")
public Student getStudent()
{
return new Student("444");
}
}
解决:destory方法不执行的原因:程序停止spirng容器并没有执行销毁的方法,因此要向jvm注册一个销毁的钩子,使用ConfigurableApplicationContext 类
public class S01 {
private static ConfigurableApplicationContext application;
public static void main(String[] args) {
// application = new ClassPathXmlApplicationContext("classpath:springcode/*.xml");
application = new AnnotationConfigApplicationContext(Config.class);
// Student bean = (Student)application.getBean("student");
// System.out.println(bean.getName();
application.start();
application.registerShutdownHook();//注册个关闭钩子才行
}
}
如果一个bean同时实现上述三种形式的调用顺序为:
- 创建bean时
- @PostConstruct 注解方式
- InitializingBean 实现接口方式
- custom init() 自定义初始化方法方式
- 销毁bean时
1. @PreDestroy 注解方式
2. DisposableBean 实现接口方式
3. custom destroy() 自定义销毁方法方式
spring bean的生命周期
Lifecycle 生命周期回掉钩子
public interface Lifecycle {
/**
* 启动当前组件
* <p>如果组件已经在运行,不应该抛出异常
* <p>在容器的情况下,这会将 开始信号 传播到应用的所有组件中去。
*/
void start();
/**
* (1)通常以同步方式停止该组件,当该方法执行完成后,该组件会被完全停止。当需要异步停
* 止行为时,考虑实现SmartLifecycle 和它的 stop(Runnable) 方法变体。
注意,此停止通知在销毁前不能保证到达:在*常规关闭时,{@code Lifecycle} bean将首先收到一个停止通知,然后才传播*常规销毁回调;然而,在*上下文的生命周期内的热刷新或中止的刷新尝试上,只调用销毁方法
对于容器,这将把停止信号传播到应用的所有组件*
*/
void stop();
/**
* 检查此组件是否正在运行。
* 1. 只有该方法返回false时,start方法才会被执行。
* 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
*/
boolean isRunning();
}
LifeCycle定义Spring容器对象的生命周期,任何spring管理对象都可以实现该接口。
然后,当ApplicationContext本身接收启动和停止信号(例如在运行时停止/重启场景)时,spring容器将在容器上下文中找出所有实现了LifeCycle及其子类接口的类,并一一调用它们实现的类。spring是通过委托给生命周期处理器LifecycleProcessor来实现这一点的。
LifecycleProcessor生命周期处理器
请注意,LifecycleProcessor本身就是LifeCycle接口的扩展。它还添加了另外两个方法来响应spring容器上下文的刷新(onRefresh)和关闭(close)。
public interface LifecycleProcessor extends Lifecycle {
/**
* 响应Spring容器上下文 refresh
*/
void onRefresh();
/**
* 响应Spring容器上下文 close
*/
void onClose();
}
Lifecycle生命周期的不足
常规的LifeCycle接口只是在容器上下文显式的调用start()/stop()方法时,才会去回调LifeCycle的实现类的start stop方法逻辑。并不意味着在上下文刷新时自动启动。
package springcode;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class S01 {
private static ConfigurableApplicationContext application;
public static void main(String[] args) {
// application = new ClassPathXmlApplicationContext("classpath:springcode/*.xml");
application = new AnnotationConfigApplicationContext(Config.class);
// Student bean = (Student)application.getBean("student");
// System.out.println(bean.getName();
application.start();
application.close();
application.registerShutdownHook();//注册个关闭钩子才行
}
}
//结果
这个组件启动了....
这个组件关闭了...
SmartLifecycle 自动生命周期扩展
那么,如果Spring容器上下文没有显式的调用start和destory(或者close,stop)等方法时,我们也需要做到生命周期回调,怎么做?
于是SmartLifecycle可以做到这一点,它继承自Lifecycle接口,新增了如下几个方法:
public interface SmartLifecycle extends Lifecycle, Phased {
/**
* 如果该`Lifecycle`类所在的上下文在调用`refresh`时,希望能够自己自动进行回调,则返回`true`* ,
* false的值表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。
*/
boolean isAutoStartup();
/**
* Indicates that a Lifecycle component must stop if it is currently running.
* <p>The provided callback is used by the {@link LifecycleProcessor} to support
* an ordered, and potentially concurrent, shutdown of all components having a
* common shutdown order value. The callback <b>must</b> be executed after
* the {@code SmartLifecycle} component does indeed stop.
* <p>The {@link LifecycleProcessor} will call <i>only</i> this variant of the
* {@code stop} method; i.e. {@link Lifecycle#stop()} will not be called for
* {@code SmartLifecycle} implementations unless explicitly delegated to within
* the implementation of this method.
* @see #stop()
* @see #getPhase()
*/
void stop(Runnable callback);
}
SmartLifecycle用于细粒度控制特定bean的自动启动(包括启动阶段)。另外,请注意,stop通知在销毁前不能保证到达,在常规关闭时,所有生命周期bean将首先收到停止通知,然后才传播一般的销毁回调;但是,在上下文生命周期内的热刷新或中止刷新尝试时,只调用销毁方法。
容器中实现了Lifecycle的多个类如果希望有顺序的进行回调时,那么启动和关闭调用的顺序可能很重要。如果任何两个对象之间存在依赖关系,那么依赖方将在依赖后开始,在依赖前停止。然而,有时直接依赖关系是未知的。您可能只知道某个类型的对象应该在另一个类型的对象之前开始。在这些情况下,SmartLifecycle接口定义了另一个选项,即在其超接口上定义的getPhase()方法。
当开始时,getPhase()返回值最小的对象先开始,当停止时,遵循相反的顺序。因此,实现SmartLifecycle的对象及其getPhase()方法返回Integer.MIN_VALUE将在第一个开始和最后一个停止。相反,MAX_VALUE将指示对象应该在最后启动并首先停止(可能是因为它依赖于要运行的其他进程)。
SmartLifecycle对象的默认phase是0。因此,任何实现类的phase的值为负数时都表明一个对象应该在这些标准的生命周期回调之前进行执行,反之亦然。
如您所见,SmartLifecycle定义的stop方法接受一个回调。在实现的关闭过程完成之后,任何实现都必须调用回调的run()方法。这允许在必要时进行异步关闭,因为LifecycleProcessor接口,即DefaultLifecycleProcessor,的默认实现,将等待每个阶段中的对象组的超时值来调用这个回调。默认的每个阶段超时为30秒。您可以通过在上下文中定义一个名为lifecycleProcessor的bean来覆盖默认的生命周期处理器实例。如果您只想修改超时,那么定义以下内容就足够了:
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
如前所述,LifecycleProcessor接口也定义了用于刷新和关闭上下文的回调方法。后者将简单地驱动关机过程,就好像已经显式地调用了stop()一样,但它将在上下文关闭时发生。另一方面,refresh回调支持SmartLifecycle bean的另一个特性。当刷新上下文(在所有对象实例化和初始化之后)时,将调用这个回调,此时,默认的生命周期处理器将检查每个SmartLifecycle对象的isAutoStartup()方法返回的布尔值。如果是true,那么该对象将在此时启动,而不是等待上下文或其自己的start()方法的显式调用(与上下文刷新不同,上下文启动不会自动发生在标准上下文实现中)。“阶段”值以及任何“依赖”关系将以如上所述的方式确定启动顺序。