玩转Spring生命周期之Lifecycle
Lifecycle callbacks
Initialization callbacks
、Destruction callbacks
要与容器的bean生命周期管理交互,即容器在启动后和容器在销毁前对每个bean执行操作,有如下三种方法:
1.实现Spring框架的InitializingBean
和DisposableBean
接口。容器为前者调用afterPropertiesSet()
方法,为后者调用destroy()
方法,以允许bean
在初始化和销毁bean
时执行某些操作。
public class HelloLifeCycle implements InitializingBean, DisposableBean { public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet 启动");
} public void destroy() throws Exception {
System.out.println("DisposableBean 停止");
}
}
2.bean自定义初始化方法和销毁方法,然后在定义bean时指定初始化方法和销毁方法
<bean id="helloLifeCycle" class="com.hzways.life.cycle.HelloLifeCycle" init-method="init3"
destroy-method="destroy3"/>
3.JSR-250 @PostConstruct和@PreDestroy注解通常被认为是在现代Spring应用程序中接PostConstruct注解用于方法上,该方法在初始化的依赖注入操作之后被执行。这个方法必须在class被放到service之后被执行,这个注解所在的类必须支持依赖注入。
public class HelloLifeCycle { @PostConstruct
private void init2() {
System.out.println("PostConstruct 启动");
} @PreDestroy
private void destroy2() {
System.out.println("PreDestroy 停止");
} }
Note:注意PostConstruct
注解用于方法上,该方法在初始化的依赖注入操作之后被执行。因此,容器必须要开启支持注解形式的依赖注入的功能,加入如下配置即可:
<context:annotation-config/>
如果一个bean同时实现上述三种形式,调用顺序为:
- 创建bean时
1. @PostConstruct 注解方式
2. InitializingBean 实现接口方式
3. custom init() 自定义初始化方法方式
- 销毁bean时
1. @PreDestroy 注解方式
2. DisposableBean 实现接口方式
3. custom destroy() 自定义销毁方法方式
Spring bean的生命周期
Startup and shutdown callbacks
结合生命周期机制,生命周期接口定义了任何具有自身生命周期需求的对象的基本方法(例如,启动和停止一些后台过程):
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
方法逻辑。并不意味着在上下文刷新时自动启动。
我们可以定义一个类实现Lifecycle
public class HelloLifeCycle implements Lifecycle {
private volatile boolean running = false; public HelloLifeCycle() {
System.out.println("构造方法!!!");
} @Override
public void start() {
System.out.println("lifycycle start");
running = true; }
@Override
public void stop() {
System.out.println("lifycycle stop");
running = false;
} @Override
public boolean isRunning() {
return running;
}
}
写一个测试类并在main
方法里面启动spring
容器,这里没有显示的调用contex
t的start()
和close()
方法
public static void main(String[] args) throws InterruptedException {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:services.xml");
}
结果是,控制台没有任何输出,容器并没有调用生命周期的回调方法.
当我们将启动容器的类,显式的加上start和stop方法后:
public static void main(String[] args) throws InterruptedException {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:services.xml");
applicationContext.start();
applicationContext.close();
}
这时我们看控制台,spring容器回调了生命周期的方法
SmartLifecycle 自动的生命周期扩展
那么,如果Spring容器上下文没有显式的调用
start
和destory
(或者close
,stop
)等方法时,我们也需要做到生命周期回调,怎么做?
于是SmartLifecycle
可以做到这一点,它继承自Lifecycle
接口,新增了如下几个方法:
public interface SmartLifecycle extends Lifecycle, Phased { /**
* 如果该`Lifecycle`类所在的上下文在调用`refresh`时,希望能够自己自动进行回调,则返回`true`* ,
* false的值表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。
*/
boolean isAutoStartup(); void stop(Runnable callback); }
容器中实现了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()
方法的显式调用(与上下文刷新不同,上下文启动不会自动发生在标准上下文实现中)。
玩转Spring生命周期之Lifecycle的更多相关文章
- Spring学习总结(4)-Spring生命周期的回调
参考文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans ...
- Android 进程生命周期 Process Lifecycle
Android 进程生命周期 Process Lifecycle 进程的生命周期 Android系统会尽力保持应用的进程,但是有时为了给新的进程和更重要的进程回收一些内存空间,它会移除一些旧的进程. ...
- spring生命周期
Github地址 最近在整合mybatis-spring. 公司里面已经有一个叫做kylin-datasource的开发包,以前能够提供master和slave2个数据源,最近更新了2.0版本,支持自 ...
- 说下spring生命周期
面试官:说下spring生命周期 程序员:不会 那你先回去等消息吧 Bean实现了BeanNameAware,Spring会将Bean的ID透传给setBeanName java.后端开发.程 ...
- Spring生命周期详解
导读 Spring中Bean的生命周期从容器的启动到停止,涉及到的源码主要是在org.springframework.context.support.AbstractApplicationContex ...
- 【源码】spring生命周期
一.spring生命周期 1. 实例化Bean 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用crea ...
- spring 生命周期最详解
转载. https://blog.csdn.net/qq_23473123/article/details/76610052 目的 在大三开始学习spring时,老师就说spring bean周期非常 ...
- Spring-IOC bean 生命周期之 Lifecycle 钩子
Lifecycle callbacks Initialization callbacks.Destruction callbacks 要与容器的bean生命周期管理交互,即容器在启动后和容器在销毁前对 ...
- 七、spring生命周期之初始化和销毁方法
一.通过@Bean指定初始化和销毁方法 在以往的xml中,我们是这样配置的 <bean id="exampleInitBean" class="examples.E ...
随机推荐
- 高校表白App-团队冲刺第六天
今天要做什么 在引导页的基础上添加小红点,并且在滑动时进行增强用户体验的修饰 做了什么 在布局中成功添加小红点,并在activity中得到实现;滑动在3/4时发生渐变,增强用户体验;滑动可回退;在最后 ...
- POJ 树的直径和重心
树的直径:(无根)树上最长两点间的最长路径,两次dfs即可,第一次dfs任选一点u,找到距离它最远的点s,再从点s进行一次dfs,找到距离s最远的点t,则s-t之间的路径就是树的直径.证明: < ...
- kafka可视化工具
Kafka可视化客户端工具(Kafka Tool 2)的安装和使用 Kafka Tool 2 是一款 Kafka 的可视化客户端工具,可以非常方便的查看 Topic 的队列信息.消费者信息以及 kaf ...
- CAS 原理 应用
原子CAS操作 原子操作指令里,有原子加,原子减,cas到底是什么呢? 首先看一段代码, bool compare_and_swap(int *accum, int *dest, int newval ...
- JS对DOM的操作优化法则
html页面显示过程 解析HTML,并生成一棵DOM tree 解析各种样式并结合DOM tree生成一棵Render tree 对Render tree的各个节点计算布局信息,比如box的位置与尺寸 ...
- ThinkPHP5 SQL注入漏洞 && 敏感信息泄露
访问看到用户名被显示了 http://192.168.49.2/index.php?ids[]=1&ids[]=2 访问http://your-ip/index.php?ids[0,updat ...
- ClickHouse与ES的优劣对比
优点: ClickHouse写入吞吐量大,单服务器日志写入量在50MB到200MB/s,每秒写入超过60w记录数,是ES的5倍以上. 查询速度快,官方宣称数据在pagecache中,单服务器查询速率大 ...
- 一键设置WPS_Office_2019专业版的定时自动备份的批处理文件
一键设置WPS_Office_2019专业版的定时自动备份的批处理文件 rem ================================================ rem 一键设置WPS ...
- 痞子衡嵌入式:ARM Cortex-M内核那些事(9.1)- 存储保护(MPU - PMSAv6/7)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是ARM Cortex-M存储保护模块(MPU). <ARM Cortex-M内核MCU开发那些事>的内核篇连载最早是 201 ...
- Go测试技术分享(一):场景化接口Case编写
一.前言 本人负责的支付清结算方向的测试工作,在测试项目中,会出现流程化的接口调用,请求完一个接口后,继续请求另一个接口(这里的接口可以指Http,也指rpc接口),这里以一个真实场景为例:用户在平台 ...