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关闭程序时,可以做到优雅停机。

外包

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注