Spring源码:Bean生命周期(终章)

简介: 本系列前面讲解了Spring的bean定义、bean实例化、bean初始化等生命周期阶段。这些步骤使我们能够了解bean从创建到准备好使用所经历的过程。但是,除了这些步骤,bean的销毁也是非常重要的一步。在本系列的最后,我们将深入探讨bean的销毁过程,包括在什么情况下会发生销毁、销毁的顺序以及如何在bean销毁之前执行一些清理任务等。通过学习bean的销毁过程,我们将更全面地了解Spring的bean生命周期。在Spring中,有多种方式可以销毁bean。其中一种方式是在应用程序关闭时显式地调用`applicationContext.close()`方法来关闭容器。这个方法将会销毁所有还没

前言

本系列前面讲解了Spring的bean定义、bean实例化、bean初始化等生命周期。这些步骤使我们能够了解bean从创建到准备好使用所经历的过程。但是,除了这些步骤,bean的销毁也是非常重要的一步。在本系列的最后,我们将深入探讨bean的销毁过程,包括在什么情况下会发生销毁、销毁的顺序以及如何在bean销毁之前执行一些清理任务等。通过学习bean的销毁过程,我们将更全面地了解Spring的bean生命周期。

在Spring中,有多种方式可以销毁bean。其中一种方式是在应用程序关闭时显式地调用applicationContext.close()方法来关闭容器。这个方法将会销毁所有还没有被销毁的bean。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

applicationContext.close();

实现DisposableBean接口

实现DisposableBean接口是一种销毁bean的简单方式。当bean容器关闭时,Spring会调用DisposableBean的destroy()方法来销毁bean。以下是一些示例代码:

import org.springframework.beans.factory.DisposableBean;
@Component
public class MyBean implements DisposableBean {
   

    @Override
    public void destroy() throws Exception {
   
        // 在这里清理资源
    }
}

使用@PreDestroy注解

使用@PreDestroy注解是另一种简单的方式来销毁bean。当bean容器关闭时,Spring会调用使用@PreDestroy注解的方法来销毁bean。以下是一些示例代码:

import javax.annotation.PreDestroy;
@Component
public class MyBean {
   

    @PreDestroy
    public void cleanUp() throws Exception {
   
        // 在这里清理资源
    }
}

registerDisposableBeanIfNecessary

registerDisposableBeanIfNecessary()方法是一个非常重要的方法,它是在bean创建后进行处理bean销毁逻辑的前提。在Spring的AbstractBeanFactory类中,该方法会检查当前bean是否实现了DisposableBean接口或者@PreDestroy注解,如果是的话,就会将该bean添加到一个DisposableBeanAdapter对象中,该对象会在bean销毁时被调用以执行销毁任务。这个过程是在bean销毁之前执行的,以确保正确关闭应用程序。

    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
   
        AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
        if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
   
            if (mbd.isSingleton()) {
   
                // Register a DisposableBean implementation that performs all destruction
                // work for the given bean: DestructionAwareBeanPostProcessors,
                // DisposableBean interface, custom destroy method.
                registerDisposableBean(beanName, new DisposableBeanAdapter(
                        bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
            }
            else {
   
                // A bean with a custom scope...
                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, acc));
            }
        }
    }

我大概讲下这个方法requiresDestruction

    protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
   
        return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
                (hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
                        bean, getBeanPostProcessorCache().destructionAware))));
    }
  1. DisposableBeanAdapter.hasDestroyMethod:校验是否实现了DisposableBean或者AutoCloseable接口,如果没有的话,再查看是否bean定义的destroyMethodName属性是(inferred),如果是的话,那么直接找这个类是否有close方法没有的话再找shutdown方法
  2. DisposableBeanAdapter.hasApplicableProcessors:是否有@PreDestroy注解

DisposableBeanAdapter

DisposableBeanAdapter对象是一个适配器,用于在销毁bean时执行必要的处理。它会将DisposableBean接口或@PreDestroy注解的方法转换为一个回调方法,以便在bean销毁时执行。这种适配器模式允许非标准的bean销毁方法与Spring框架协同工作。

在将DisposableBeanAdapter对象添加到一个DisposableBeanRegistry对象中时,Spring会将该对象添加到一个bean销毁的注册表中。当需要销毁所有bean时,Spring就会从该注册表中获取所有需要销毁的bean,并按照正确的顺序执行销毁任务。这样就可以确保应用程序的正确关闭。

destroySingleton

当Spring程序关闭时,会调用destroyBeans方法,这里我们分析关键部分代码:

    public void destroySingleton(String beanName) {
   
        // Remove a registered singleton of the given name, if any.
        // 先从单例池中移除掉
        removeSingleton(beanName);

        // Destroy the corresponding DisposableBean instance.
        DisposableBean disposableBean;
        synchronized (this.disposableBeans) {
   
            disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
        }
        destroyBean(beanName, disposableBean);
    }
  1. removeSingleton:先从单例池中移除掉
  2. this.disposableBeans.remove:这里返回的是我们之前调用registerDisposableBeanIfNecessary方法添加进去的DisposableBeanAdapter适配器
  3. destroyBean:直接销毁bean,这里注意一个小点就是如果当前bean被其他bean依赖了,那么先移除销毁其他Bean,然后就是调用适配器的destroy方法

总结

非常感谢您对 Spring 生命周期系列文章的关注和支持,我们在过去一个月中深入了解了 Spring 框架中 Bean 的生成、初始化、后置处理和销毁等过程,对于理解 Spring 框架的原理和机制非常有帮助。我们总结一下Spring到底做了那些事情将bean从生成到销毁的全过程:

  1. 项目启动时,ClassPathBeanDefinitionScanner扫描得到所有BeanDefinition,由于ACM技术所以此时beanclass属性为String类型的bean的名称
  2. 获取合并后的BeanDefinition
  3. beanClass开始真正的被加载替换原有String类型的bean的名称
  4. 调用实例化前处理方法applyBeanPostProcessorsBeforeInstantiation
  5. 通过构造方法创建Bean实例
  6. 后置处理合并后的BeanDefinition,调用postProcessMergedBeanDefinition(寻找注入点)
  7. 调用实例化后处理方法postProcessAfterInstantiation
  8. 开始进行属性注入:postProcessProperties
  9. 调用初始化前处理方法:applyBeanPostProcessorsBeforeInitialization
  10. 进行初始化:invokeInitMethods,会调用指定init方法或者afterPropertiesSet方法
  11. 调用初始化后处理方法:applyBeanPostProcessorsAfterInitialization(AOP)
  12. 容器关闭时,走bean的销毁逻辑,即今天所讲

这里面有很多逻辑流程我都在单独的文章中有细讲,比如FactoryBean、PropertyValues等等,由于是总结所以就不全写出来了,也希望大家可以好好理解Spring源码,下一步,我们将会着重讲解 Bean 的属性依赖注入。

相关文章
|
14天前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
96 26
|
1月前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
2月前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
2月前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
2月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
73 6
|
2月前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
157 3
|
2月前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
74 2
|
2月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
50 1
|
27天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
201 17
Spring Boot 两种部署到服务器的方式
|
27天前
|
Dart 前端开发 JavaScript
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
59 17
springboot自动配置原理