Spring应用上下文生命周期详解及源码分析,Spring IOC容器启动及关闭过程超详细解释(下)
Release调试
文章目录
单链表
书接上文
Spring应用上下文生命周期详解及源码分析,Spring IOC容器启动及关闭过程超详细解释(上)
appID
Spring应用上下文生命周期详解及源码分析,Spring IOC容器启动及关闭过程超详细解释(下)
程序员英文简历
十三、Spring 应用上下文启动阶段
AbstractApplicationContext#start() 方法:
mcu
// org.springframework.context.support.AbstractApplicationContext#start
@Override
public void start() {
// 启动 LifecycleProcessor(依赖查找 Lifecycle Beans、启动 Lifecycle Beans)
getLifecycleProcessor().start();
// 发布 Spring 应用上下文已启动事件 - ContextStartedEvent
publishEvent(new ContextStartedEvent(this));
}
该方法并不是必须要调用的,如果想用,必须显式的调用,多用于发布一些事件等。
Delphi 证书
十四、Spring 应用上下文停止阶段
AbstractApplicationContext#stop() 方法:
双系统
// org.springframework.context.support.AbstractApplicationContext#stop
@Override
public void stop() {
// 停止 LifecycleProcessor(依赖查找 Lifecycle Beans、停止 Lifecycle Beans)
getLifecycleProcessor().stop();
// 发布 Spring 应用上下文已停止事件 - ContextStoppedEvent
publishEvent(new ContextStoppedEvent(this));
}
该方法并不是必须要调用的,如果想用,必须显式的调用,多用于发布一些事件等。
持久层框架
1、代码实例
import org.springframework.context.Lifecycle;
/**
* 自定义 {@link Lifecycle} 实现
*/
public class MyLifecycle implements Lifecycle {
private boolean running = false;
@Override
public void start() {
running = true;
System.out.println("MyLifecycle 启动...");
}
@Override
public void stop() {
running = false;
System.out.println("MyLifecycle 停止...");
}
@Override
public boolean isRunning() {
return running;
}
}
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.Lifecycle;
import org.springframework.context.support.GenericApplicationContext;
/**
* 自定义 {@link Lifecycle} Bean 示例
*/
public class LifecycleDemo {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
// 注解 MyLifecycle 成为一个 Spring Bean
context.registerBeanDefinition("myLifecycle", BeanDefinitionBuilder.rootBeanDefinition(MyLifecycle.class).getBeanDefinition());
// 刷新 Spring 应用上下文
context.refresh();
// 启动 Spring 应用上下文
context.start();
// 停止 Spring 应用上下文
context.stop();
// 关闭 Spring 应用
context.close();
}
}
运行结果:
科技
MyLifecycle 启动…
MyLifecycle 停止…Shader
2、总结
使用Lifecycle 的方式其实并不友好,它是一个同步的方式监听,不如使用Listener监听器的方式,对一些长时间阻塞的方法可以使用异步的方式进行操作。
StarRocks
十五、Spring 应用上下文关闭阶段
Spring 应用上下文关闭阶段,就是AbstractApplicationContext#close() 方法。
测试覆盖率
// org.springframework.context.support.AbstractApplicationContext#close
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
// 注销 Shutdown Hook 线程(如果曾注册)(2、)
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}
// org.springframework.context.support.AbstractApplicationContext#doClose
protected void doClose() {
// Check whether an actual close attempt is necessary...
// 状态标识:active(false)、closed(true)
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isDebugEnabled()) {
logger.debug("Closing " + this);
}
// Live Beans JMX 撤销托管
LiveBeansView.unregisterApplicationContext(this);
try {
// Publish shutdown event.
// 发布 Spring 应用上下文已关闭事件 - ContextClosedEvent
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
// 关闭 LifecycleProcessor(依赖查找 Lifecycle Beans、停止 Lifecycle Beans)
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}
// Destroy all cached singletons in the context's BeanFactory.
// 销毁 Spring Beans(见 1、)
destroyBeans();
// Close the state of this context itself.
// 关闭 BeanFactory,将id设为null、beanFactory设为null
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
// 回调 onClose()
onClose();
// Reset local application listeners to pre-refresh state.
// 清除Listener
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Switch to inactive.
this.active.set(false);
}
}
1、销毁 Spring Beans
会调用DefaultListableBeanFactory的destroySingletons。
其他
// org.springframework.beans.factory.support.DefaultListableBeanFactory#destroySingletons
@Override
public void destroySingletons() {
super.destroySingletons();
updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
clearByTypeCache();
}
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingletons
public void destroySingletons() {
if (logger.isTraceEnabled()) {
logger.trace("Destroying singletons in " + this);
}
synchronized (this.singletonObjects) {
this.singletonsCurrentlyInDestruction = true;
}
String[] disposableBeanNames;
synchronized (this.disposableBeans) {
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
destroySingleton(disposableBeanNames[i]); // bean销毁
}
this.containedBeanMap.clear();
this.dependentBeanMap.clear();
this.dependenciesForBeanMap.clear();
clearSingletonCache();
}
我们会发现,会清除所有bean的缓存,并且走Bean的销毁生命周期:
Spring Bean生命周期——从源码角度详解Spring Bean的生命周期(下)
情感分析
这里只处理单例的bean,原型bean实际上已经脱离了spring容器的管理。
代码
2、注销 Shutdown Hook 线程(如果曾注册)
首先shutdownHook注册,可以调用registerShutdownHook方法进行注册:
props属性详解
// org.springframework.context.support.AbstractApplicationContext#registerShutdownHook
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
我们注意到,注册shutdownHook 时,会定义一个线程,该线程的run方法中调用了doClose()方法,相当于信号到达时,会执行doClose方法。
java-rocketmq
代码实例
GenericApplicationContext context = new GenericApplicationContext();
context.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
@Override
public void onApplicationEvent(ContextClosedEvent event) {
System.out.printf("[线程 %s] ContextClosedEvent 处理\n", Thread.currentThread().getName());
}
});
// 刷新 Spring 应用上下文
context.refresh();
// 注册 Shutdown Hook
context.registerShutdownHook();
System.out.println("按任意键继续并且关闭 Spring 应用上下文");
System.in.read();
// 关闭 Spring 应用(同步)
context.close();
实际上,springboot启动时,也会默认注册一个ShutdownHook与操作系统绑定,当使用kill关闭程序时,可以做到优雅停机。
外包