生命周期流程
在前面的文章一个 Bean 就这样走完了它的一生之 Bean 的出生里面讲解了 Spring 中 Bean 的创建的生命周期,这篇文章再来看一下 Bean 销毁的生命周期。在 Spring 容器被关闭的时候,会调用依次调用 Bean 销毁的生命周期方法,如下图所示:
案例解析
数据库连接池在 Bean 销毁时主动关闭连接
假设现在定义了一个数据库连接池相关的 Bean,使用了 @PreDestroy 注解修饰了它的 shutdown() 方法,当 Spring 容器销毁的时候,它的 shutdown() 方法就会调用,以便实现在程序终止的时候关闭和数据库创建的连接。代码如下:- @Component
- public class DatabaseConnectionPool {
- private final String url = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1";
- private final String username = "sa";
- private final String password = "";
- private final int initialPoolSize = 5;
- private Queue<Connection> connectionPool;
- private List<Connection> activeConnections;
- public DatabaseConnectionPool() {
- this.connectionPool = new ConcurrentLinkedQueue<>();
- this.activeConnections = new ArrayList<>();
- }
- @PostConstruct
- public void init() {
- //初始化连接
- }
- @PreDestroy
- public void shutdown() {
- for (Connection conn : activeConnections) {
- try {
- if (conn != null && !conn.isClosed()) {
- conn.close();
- System.out.println("DatabaseConnectionPool: 关闭连接: " + conn);
- }
- } catch (SQLException e) {
- System.err.println("DatabaseConnectionPool: 关闭连接失败: " + e.getMessage());
- }
- }
- connectionPool.clear();
- activeConnections.clear();
- }
- }
复制代码 Bean 销毁源码解析
DisposableBean 的注册
在 Bean 创建的过程中,在 AbstractAutowireCapableBeanFactory 的 doCreateBean() 方法中会判断一个 Bean 是否应该在容器关闭的时候被销毁,如果需要的话就会为当前 Bean 注册一个 DisposableBeanAdapter的对象。代码如下:- protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
- //这里判断
- if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
- if (mbd.isSingleton()) {
- //这里创建了一个 DisposableBeanAdapter 对象
- registerDisposableBean(beanName, new DisposableBeanAdapter(
- bean, beanName, mbd, getBeanPostProcessorCache().destructionAware));
- }
- else {
- Scope scope = this.scopes.get(mbd.getScope());
- if (scope == null) {
- throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
- }
- scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
- bean, beanName, mbd, getBeanPostProcessorCache().destructionAware));
- }
- }
- }
复制代码 在判断的时候首先会判断 Bean 是否有销毁方法。主要是在 hasDestroyMethod() 方法中实现的。在该方法中判断一个 Bean 是否实现了 DisposableBean 接口或者是否有定义销毁方法,而判断是否有销毁方法则是通过判断 Bean 定义中的 destroyMethodNames 属性不为空来实现的。这个属性的值就是解析 @Bean 注解的 destroyMethod 属性配置的方法或者XML中的destroy-method 配置的方法。代码如下:- protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
- return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
- (hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
- bean, getBeanPostProcessorCache().destructionAware))));
- }
- public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
- //这里判断是否实现了DisposableBean接口
- return (bean instanceof DisposableBean ||
- inferDestroyMethodsIfNecessary(bean.getClass(), beanDefinition) != null);
- }
-
- static String[] inferDestroyMethodsIfNecessary(Class<?> target, RootBeanDefinition beanDefinition) {
- //这里判断Bean定义的destroyMethodNames是否不为空,而destroyMethodNames就是
- //解析@Bean的destroyMethod属性配置的方法或者XML中的destroy-method配置的方法
- String[] destroyMethodNames = beanDefinition.getDestroyMethodNames();
- if (destroyMethodNames != null && destroyMethodNames.length > 1) {
- return destroyMethodNames;
- }
- //省略代码
- }
复制代码 然后就会判断是否有 DestructionAwareBeanPostProcessor,如果有的话,则会调用它的 requiresDestruction() 进行判断。而 @PreDestroy 注解修饰的方法就是由 InitDestroyAnnotationBeanPostProcessor 来进行真实的判断的,而它的父类是我们的老朋友 CommonAnnotationBeanPostProcessor,在它的构造函数中初始化了要处理 @PreDestroy 注解。代码如下:- class DisposableBeanAdapter {
- public static boolean hasApplicableProcessors(Object bean, List<DestructionAwareBeanPostProcessor> postProcessors) {
- if (!CollectionUtils.isEmpty(postProcessors)) {
- for (DestructionAwareBeanPostProcessor processor : postProcessors) {
- //这里调用requiresDestruction()方法进行判断
- if (processor.requiresDestruction(bean)) {
- return true;
- }
- }
- }
- return false;
- }
- }
- public class InitDestroyAnnotationBeanPostProcessor {
- public boolean requiresDestruction(Object bean) {
- return findLifecycleMetadata(bean.getClass()).hasDestroyMethods();
- }
- private LifecycleMetadata findLifecycleMetadata(Class<?> beanClass) {
- if (this.lifecycleMetadataCache == null) {
- // Happens after deserialization, during destruction...
- return buildLifecycleMetadata(beanClass);
- }
- // Quick check on the concurrent map first, with minimal locking.
- LifecycleMetadata metadata = this.lifecycleMetadataCache.get(beanClass);
- if (metadata == null) {
- synchronized (this.lifecycleMetadataCache) {
- metadata = this.lifecycleMetadataCache.get(beanClass);
- if (metadata == null) {
- metadata = buildLifecycleMetadata(beanClass);
- this.lifecycleMetadataCache.put(beanClass, metadata);
- }
- return metadata;
- }
- }
- return metadata;
- }
- }
- public class CommonAnnotationBeanPostProcessor {
- public CommonAnnotationBeanPostProcessor() {
- setOrder(Ordered.LOWEST_PRECEDENCE - 3);
- // Jakarta EE 9 set of annotations in jakarta.annotation package
- addInitAnnotationType(loadAnnotationType("jakarta.annotation.PostConstruct"));
- addDestroyAnnotationType(loadAnnotationType("jakarta.annotation.PreDestroy"));
- // Tolerate legacy JSR-250 annotations in javax.annotation package
- addInitAnnotationType(loadAnnotationType("javax.annotation.PostConstruct"));
- addDestroyAnnotationType(loadAnnotationType("javax.annotation.PreDestroy"));
- // java.naming module present on JDK 9+?
- if (jndiPresent) {
- this.jndiFactory = new SimpleJndiBeanFactory();
- }
- }
- }
复制代码 JVM 虚拟机 ShutdownHook 注册
在 Spring 的 AbstractApplicationContext 中提供了一个 registerShutdownHook() 的方法,它可以向 JVM 注册一个钩子线程,在 JVM 进程终止的时候启动这个线程,完成对容器的销毁操作。在我们的业务代码中可以手动调用这个方法注册。代码如下:- public class AbstractApplicationContext {
- public void registerShutdownHook() {
- if (this.shutdownHook == null) {
- // No shutdown hook registered yet.
- this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
- @Override
- public void run() {
- if (isStartupShutdownThreadStuck()) {
- active.set(false);
- return;
- }
- startupShutdownLock.lock();
- try {
- doClose();
- }
- finally {
- startupShutdownLock.unlock();
- }
- }
- };
- Runtime.getRuntime().addShutdownHook(this.shutdownHook);
- }
- }
- }
- public clas SpringTest {
- public static void main(String[] args) {
- // 1. 创建并初始化 Spring 容器
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
- // 2. 注册 JVM 关闭Hook
- // 这一步是显式调用的,由开发者决定何时执行
- context.registerShutdownHook();
- }
- }
复制代码 而在 Spring Boot 项目中则提供了 SpringApplicationShutdownHook 回调类,在 Spring Boot 项目启动时,通过判断 spring.main.register-shutdown-hook 来决定是否注册回调。代码如下:- public class SpringApplication {
- public ConfigurableApplicationContext run(String... args) {
- Startup startup = Startup.create();
- if (this.properties.isRegisterShutdownHook()) {
- SpringApplication.shutdownHook.enableShutdownHookAddition();
- }
- }
- private void refreshContext(ConfigurableApplicationContext context) {
- if (this.properties.isRegisterShutdownHook()) {
- shutdownHook.registerApplicationContext(context);
- }
- refresh(context);
- }
- }
- class SpringApplicationShutdownHook implements Runnable {
- void registerApplicationContext(ConfigurableApplicationContext context) {
- addRuntimeShutdownHookIfNecessary();
- synchronized (SpringApplicationShutdownHook.class) {
- assertNotInProgress();
- context.addApplicationListener(this.contextCloseListener);
- this.contexts.add(context);
- }
- }
- private void addRuntimeShutdownHookIfNecessary() {
- if (this.shutdownHookAdditionEnabled && this.shutdownHookAdded.compareAndSet(false, true)) {
- addRuntimeShutdownHook();
- }
- }
- void addRuntimeShutdownHook() {
- Runtime.getRuntime().addShutdownHook(new Thread(this, "SpringApplicationShutdownHook"));
- }
-
- @Override
- public void run() {
- Set<ConfigurableApplicationContext> contexts;
- Set<ConfigurableApplicationContext> closedContexts;
- List<Handler> handlers;
- synchronized (SpringApplicationShutdownHook.class) {
- this.inProgress = true;
- contexts = new LinkedHashSet<>(this.contexts);
- closedContexts = new LinkedHashSet<>(this.closedContexts);
- handlers = new ArrayList<>(this.handlers.getActions());
- Collections.reverse(handlers);
- }
- //这里调用了容器的closeAndWait方法
- contexts.forEach(this::closeAndWait);
- closedContexts.forEach(this::closeAndWait);
- handlers.forEach(Handler::run);
- }
- }
复制代码 Bean 销毁方法调用
注册的回调线程启动的时候会调用 AbstractApplicationContext 的 doClose() 方法,然后调用 destroyBeans() 方法,然后会调用到 DefaultSingletonBeanRegistry 的 destroySingletons() 方法。代码如下:- public abstract class AbstractApplicationContext {
- protected void doClose() {
- // Check whether an actual close attempt is necessary...
- if (this.active.get() && this.closed.compareAndSet(false, true)) {
- //省略代码
- // Destroy all cached singletons in the context's BeanFactory.
- destroyBeans();
- }
-
- protected void destroyBeans() {
- getBeanFactory().destroySingletons();
- }
- }
- public class DefaultSingletonBeanRegistry {
- public void destroySingletons() {
- 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]);
- }
- this.containedBeanMap.clear();
- this.dependentBeanMap.clear();
- this.dependenciesForBeanMap.clear();
- this.singletonLock.lock();
- try {
- clearSingletonCache();
- }
- finally {
- this.singletonLock.unlock();
- }
- }
- }
复制代码 在 DefaultSingletonBeanRegistry 的 destroySingletons() 方法会循环调用之前注册的 DisposableBeanAdapter 的 destroy() 方法,在该方法中实现了对销毁生命周期方法的调用。这里面首先调用的是 DestructionAwareBeanPostProcessor 的 postProcessBeforeDestruction() 方法,在该方法中实现了对 @PreDestroy 注解修饰的方法的调用,然后调用 DisposableBean 的 destroy() 方法,最后再调用自定义的销毁方法。代码如下:- public void destroy() {
- if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
- for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
- //调用DestructionAwareBeanPostProcessor的postProcessBeforeDestruction()方法
- processor.postProcessBeforeDestruction(this.bean, this.beanName);
- }
- }
- if (this.invokeDisposableBean) {
- try {
- //调用DisposableBean的destroy()方法
- ((DisposableBean) this.bean).destroy();
- }
- catch (Throwable ex) {
-
- }
- } else if (this.destroyMethods != null) {
- for (Method destroyMethod : this.destroyMethods) {
- //调用自定义初始化方法
- invokeCustomDestroyMethod(destroyMethod);
- }
- }
-
- }
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |