Spring Bean 的生命周期了解么?

news2025/4/7 10:52:43

Spring Bean 的生命周期基本流程

一个Spring的Bean从出生到销毁的全过程就是他的整个生命周期,

img

整个生命周期可以大致分为3个大的阶段 :

  • 创建

  • 使用

  • 销毁

还可以分为5个小步骤 :

实例化(Bean的创建) , 初始化赋值, 注册Destruction回调 , Bean的正常使用 以及 Bean的销毁

Bean的创建和初始化赋值是分开的

具体代码实现 :

Spring容器在进行实例化的时候,会将xml配置的< bean > 的信息封装成一个BeanDefinition对象, Spring根据BeanDefinition来创建Bean对象,里面有很多的属性来描述Bean

  • beanClassName : bean的类名

  • initMethodName : 初始化方法名称

  • properryValues : bean的属性值

  • scope : 作用域

  • lazyInit : 延迟初始化

  1. 实例化Bean(实例化阶段)

    • Spring容器首先创建Bean实例

    • 调用Bean的构造函数,来实例化Bean对象

      • Spring在这一步创建Bean实例。 主要代码在AbstractAutowireCapableBeanFactory类中的createBeanInstance方法中实现

        就是先确保这个Bean对应的类已经被加载,然后确保他是public的,然后如果有工厂方法,则直接调用工厂方法创建Bean,如果没有的话就调用它的构造方法来创建这个Bean.

        这里需要注意的是 ,在Spring的完整Bean创建和初始化流程中,容器会在调用createBeanInstance之前检查Bean定义的作用域。如果是Singleton,容器会在其内部单例缓存中查找现有实例。如果实例已经存在,他将被重用;如果不存在,才会调用createBeanInstance来创建新的实例;

  2. (依赖注入)设置属性值(初始化阶段)

    • Spring容器注入必要的属性到Bean中

      • populateBean方法是Spring Bean生命周期中的一个关键部分,负责将属性值应用到新创建的Bean实例。他处理了自动装配,属性注入,依赖检查等多个方面 . 就是把各种属性进行初始化

  3. 检查Aware

    • 如果Bean实现了BeanNameAware , BeanClassLoaderAware等这些Aware接口, Spring容器会调用它们

      • BeanNameAware :通过这个接口,Bean可以获取到自己在Spring容器中的名字。这对于需要根据Bean的名称某些操作的常见很有用

      • ApplicationContextAware: 获取ApplicationContext对象;

      • BeanFactoryAware : 通过这个接口可以获取对BeanFactory的引用,获得对BeanFactory的访问权限

  4. 调用BeanPostProcessor前置处理方法 (初始化之前进行回调)

    • 在Bean初始化之前, 允许自定义的BeanPostProcessor对Bean实例进行处理,如修改Bean的状态. BeanPostProcessor的postProcessBeforeInitialization方法会在此时被调用

  5. 执行初始化方法

    1. 调用InitializingBean的afterPropertiesSet方法

      • 提供一个机会, 在所有Bean属性设置完成后进行初始化操作, 如果Bean实现了InitializingBean接口, afterPropertiesSet方法会被调用

      • 主要作用就是帮助我们在Bean的初始化前添加一些自己的逻辑处理,Spring内置了很多BeanPostProcessor,我们也可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中;

    2. 调用自定义init-method方法(初始化方法)

      • 提供一种配置方式, 在xml配置中指定Bean的初始化方法. 如果Bean在配置文件中定义了初始化方法,那么该方法就会被调用

  6. 调用BeanPostProcessor的后置处理方法 (Spring中对类进行增强的时候(AOP),就会使用后置处理器) --> AOP底层使用了动态代理和CGLB动态代理

    • 在Bean初始化之后,再次允许BeanPostProcessor对Bean进行处理. BeanPostProcessor的postProcessAfterInitialization方法会在此时被调用

  7. 注册Destruction回调

    • 如果Bean实现了DIsposableBean接口或者bean定义中指定了自定义的销毁方法,Spring容器会为这些Bean注册一个销毁回调,确保在容器关闭的时候能够正确的清理资源

  8. Bean准备就绪(Bean的使用阶段)

    • 此时,Bean已经完全初始化,可以开始处理应用程序的请求了

  9. 调用DisposableBean的destroy方法(Bean的销毁阶段)

    • 当容器关闭的时候, 如果Bean实现了DisposableBean接口, destroy方法会被调用

    • 在DisposableBeanAdapter的destroy方法中实现

  10. 调用自定义的destroy-method 当容器要进行关闭的时候,对象就会进入销毁阶段 ,最典型的就是,如果你使用了@PreDestroy注解,这个方法就是销毁方法 , Spring容器关闭的时候就会调用这个自定义的销毁方法

    • 如果Bean在配置文件中定义了销毁方法, 那么该方法就会被调用

    • 在DisposableBeanAdapter的destroy方法中实现

可以看到, 整个Bean的创建的过程都依赖于AbstractAutowireCapableBeanFactory这个类,而销毁主要依赖于DisposableBeanAdapter这个类

代码实践

package com.sfx.spring6;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sfx
 * Date: 2024-02-20
 * Time: 21:20
 */
public class CatDog implements BeanNameAware, InitializingBean, DisposableBean {
    private String name;

    public CatDog() {
        System.out.println("1. 实例化Bean");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("2. 执行了set方法, 设置相关属性");
        this.name = name;
    }

    
    public void myInit() {
        System.out.println("6. 执行了自定义初始化方法");
    }

    public void myDestroy() {
        System.out.println("10. 执行了自定义的销毁方法");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3. 执行了 BeanNameAware");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("5. 执行afterPropertiesSet");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("9. 执行了DisposableBean");
    }
}
package com.sfx.spring6;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sfx
 * Date: 2024-02-20
 * Time: 21:20
 */
public class CatDog implements BeanNameAware, InitializingBean, DisposableBean {
    private String name;

    public CatDog() {
        System.out.println("1. 实例化Bean");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("2. 执行了set方法, 设置相关属性");
        this.name = name;
    }


    public void myInit() {
        System.out.println("6. 执行了自定义初始化方法");
    }

    public void myDestroy() {
        System.out.println("10. 执行了自定义的销毁方法");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3. 执行了 BeanNameAware");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("5. 执行afterPropertiesSet");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("9. 执行了DisposableBean");
    }
}
package com.sfx.spring6;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sfx
 * Date: 2024-02-20
 * Time: 21:23
 */
public class App {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        CatDog bean = applicationContext.getBean(CatDog.class);
        String name = bean.getName();
        System.out.println("8. 使用了Bean  , " + name);
        ((ClassPathXmlApplicationContext) applicationContext).close();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

     <!-- 在spring中创建对象 -->

    <!-- 配置 dog 这个Bean-->
    <bean id = "catDog" class="com.sfx.spring6.CatDog" init-method="myInit" destroy-method="myDestroy">
        <property name="name" value="张三"></property>
    </bean>

    <bean id="processor" class="com.sfx.spring6.Processor">
    </bean>

</beans>

项目中会用到哪些流程呢 ? 

我们在项目中一般等到项目初始化完成后立马执行一些动作, 比如RocketMQ开启消费者,还有等等我们需要在项目初始化完成之后就要执行一些动作,我们就可以调用 InitializingBean 的afterPropertiesSet方法

好的记忆方法

我们可以给面试官这么讲解, SpringBean的生命周期分为三个大的阶段 

  • 创建
  • 使用
  • 销毁

如果划分为具体的细的5个阶段 :

  • 实例化
  • 初始化(依赖注入)
  • 注册Destruction的回调
  • Bean的使用
  • Bean的销毁

然后我们再来了解每一个阶段都要做哪些事情

  • 实例化
    • 首先会根据扫描我们写的xml,将一些属性设置到BeanDefination对象上,然后调用构造方法创建出一个Bean
  • 初始化
    • 给Bean设置属性(此时会调用bean的set方法)
    • 检查有没有实现以aware结尾的相关接口
      • BeanNameAware :通过这个接口,Bean可以获取到自己在Spring容器中的名字。这对于需要根据Bean的名称某些操作的常见很有用

      • ApplicationContextAware: 获取ApplicationContext对象;

      • BeanFactoryAware : 通过这个接口可以获取对BeanFactory的引用,获得对BeanFactory的访问权限

    • 执行初始化前置方法

    • 执行初始化方法  (有两个, 首先先会调用 InitializingBean 的afterPropertiesSet方法,然后会调用自己定义的初始化方法)

    • 执行初始化后置方法

    • 注册Destruction的回调

      • 如果Bean实现了DIsposableBean接口或者bean定义中指定了自定义的销毁方法,Spring容器会为这些Bean注册一个销毁回调,确保在容器关闭的时候能够正确的清理资源

    • 开始使用Bean

    • 调用DisposableBean的destroy方法(Bean的销毁阶段)

      • 当容器关闭的时候, 如果Bean实现了DisposableBean接口, destroy方法会被调用

      • 在DisposableBeanAdapter的destroy方法中实现

    • 调用自定义的destroy-method 当容器要进行关闭的时候,对象就会进入销毁阶段 ,最典型的就是,如果你使用了@PreDestroy注解(对于SpringBoot),这个方法就是销毁方法 , Spring容器关闭的时候就会调用这个自定义的销毁方法

      • 如果Bean在配置文件中定义了销毁方法, 那么该方法就会被调用

      • 在DisposableBeanAdapter的destroy方法中实现

对于SpringBoot而言,如果你想要在实例化和依赖注入完成后进行初始化操作,可以加@PostConstruct注解 ,当然也可以使用 InitializingBean 的afterPropertiesSet方法

如果你想要自定义销毁方法 , 可以加 @PreDestroy注解

下次分享再见~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1460389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能_CPU安装运行ChatGLM大模型_安装清华开源人工智能AI大模型ChatGlm-6B_004---人工智能工作笔记0099

上一节003节我们安装到最后,本来大模型都可以回答问题了,结果, 5分钟后给出提示,需要GPU,我去..继续看官网,如何配置CPU运行 没办法继续看: https://github.com/THUDM/ChatGLM-6B 这里是官网可以看到 需要gcc的版本是11.3.0,这里我们先没有去安装,直接试试再说 yum instal…

jenkins配置ssh的时候测试连接出现Algorithm negotiation fail

背景&#xff1a;当jenkins升级后&#xff0c;同时ssh插件也升级&#xff0c;测试ssh连接的时候 出现的问题&#xff1a; com.jcraft.jsch.JSchAlgoNegoFailException: Algorithm negotiation fail: algorithmName"server_host_key" jschProposal"ecdsa-sha2-n…

Linux环境搭建Jenkins(详细图文)

目录 简介Jenkins 特点 一、环境准备 1.jdk环境准备 2.maven环境准备 3.git环境准备 二、安装部署Jenkins&#xff08;采用war包方式&#xff09; 1.下载Jenkins ​2.启动war包 1&#xff09;将下载好的Jenkins的war包上传到服务器上 2&#xff09;编辑启动脚本,方便…

Go语言的100个错误使用场景(48-54)|错误管理

前言 大家好&#xff0c;这里是白泽。**《Go语言的100个错误以及如何避免》**是最近朋友推荐我阅读的书籍&#xff0c;我初步浏览之后&#xff0c;大为惊喜。就像这书中第一章的标题说到的&#xff1a;“Go: Simple to learn but hard to master”&#xff0c;整本书通过分析1…

SpringBoot项目如何打包成docker镜像?

将Spring Boot项目打包成Docker镜像的过程可以分为以下几个步骤&#xff1a; 1. 创建Dockerfile 首先&#xff0c;你需要在Spring Boot项目的根目录下创建一个Dockerfile。这个文件包含了Docker镜像构建的所有指令。一个基本的Dockerfile可能看起来像这样&#xff1a; # 使用…

flink sql 实战实例 及延伸问题:聚合/数据倾斜/DAU/Hive流批一体 等

flink sql 实战实例 及延伸问题 Flink SQL 计算用户分布Flink SQL 计算 DAU多topic 数据更新mysql topic接入mysql引入 upsert-kafka-connector 以1.14.4版本为例 数据倾斜问题&#xff1a;让你使用用户心跳日志&#xff08;20s 上报一次&#xff09;计算同时在线用户、DAU 指标…

Github代码仓库SSH配置流程

作者&#xff1a; Herman Ye Auromix 测试环境&#xff1a; Ubuntu20.04 更新日期&#xff1a; 2024/02/21 注1&#xff1a; Auromix 是一个机器人爱好者开源组织。 注2&#xff1a; 由于笔者水平有限&#xff0c;以下内容可能存在事实性错误。 相关背景 在为Github代码仓库配…

秦岭天台山隧道群荣获交通运输部科技示范工程,恒星科通群载波应急广播与无线调度系统产品应用其中

2023年9月12日&#xff0c;全国交通运输科技示范工程现场推进会在河南省平顶山市召开&#xff0c;会上为全国已通过验收的10项科技示范工程进行了授牌&#xff0c;其中由陕西交控集团负责实施的“秦岭天台山超长隧道群安全绿色科技示范工程”名列其中。 该科技示范工程为陕西省…

2024牛客寒假算法基础集训营4(视频讲解题目)

2024牛客寒假算法基础集训营4&#xff08;视频讲解题目&#xff09; 视频链接ABCDEFG、H&#xff08;下面是hard版本的代码两个都可以过&#xff09; 视频链接 2024牛客寒假算法基础集训营4&#xff08;视频讲解题目&#xff09; A #include<bits/stdc.h> #define en…

为全志D1开发板移植LVGL日历控件和显示天气

利用TCP封装HTTP包请求天气信息 Linux还真是逐步熟悉中&#xff0c;现在才了解到Linux即没有原生的GUI&#xff0c;也没有应用层协议栈&#xff0c;所以要实现HTTP应用&#xff0c;必须利用TCP然后自己封装HTTP数据包。本篇即记录封装HTTP数据包&#xff0c;到心知天气请求天气…

亿道丨三防平板电脑厂家丨三防平板PDA丨三防工业平板:数字时代

在当今数字化时代&#xff0c;我们身边的世界变得越来越依赖于智能设备和无线连接。其中&#xff0c;三防平板PDA&#xff08;Personal Digital Assistant&#xff09;作为一种功能强大且耐用的数字工具&#xff0c;正在引领我们进入数字世界的全新征程。 三防平板PDA结合了平板…

在Win系统部署WampServer并实现公网访问本地服务【内网穿透】

目录 推荐 前言 1.WampServer下载安装 2.WampServer启动 3.安装cpolar内网穿透 3.1 注册账号 3.2 下载cpolar客户端 3.3 登录cpolar web ui管理界面 3.4 创建公网地址 4.固定公网地址访问 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0…

【Pytorch深度学习开发实践学习】B站刘二大人课程笔记整理lecture02 线性模型

课程网址 Pytorch深度学习实践 部分课件内容&#xff1a; 代码部分如下&#xff1a; import numpy as np import matplotlib.pyplot as pltx_data [1.0,2.0,3.0] y_data [2.0,4.0,6.0]def forward(x):return x * wdef loss(x,y):y_pred forward(x)return (y_pred - y) ** …

vue实现列表自动无缝滚动列表

大家好&#xff0c;今天给大家分享的知识是vue基于vue-seamless-scroll实现自动无缝滚动列表 一、实现自动滚动 最近在开发过程中遇到一个问题&#xff0c;就是需要实现自动滚动列表&#xff0c;效果图如下 就是这样一个列表在自动循环展示。在这里我是运用的 vue-seamless-sc…

Springboot AOP开发

Springboot AOP开发 一 AOP概述 AOP&#xff0c;即面向切面编程&#xff0c;简言之&#xff0c;面向方法编程。 针对方法&#xff0c;在方法的执行前或执行后使用&#xff0c;用于增强方法&#xff0c;或拓展。 二 AOP开发 1.引入 spring-boot-starter-aop 在SpringBoot项…

计算机视觉基础【OpenCV轻松入门】:获取图像的ROI

OpenCV的基础是处理图像&#xff0c;而图像的基础是矩阵。 因此&#xff0c;如何使用好矩阵是非常关键的。 下面我们通过一个具体的实例来展示如何通过Python和OpenCV对矩阵进行操作&#xff0c;从而更好地实现对图像的处理。 ROI&#xff08;Region of Interest&#xff09;是…

十三、集合进阶——单列集合 及 数据结构

单列集合 及 数据结构 13.1 集合体系结构13.1.2 单列集合1. Collection2.Collection 的遍历方式迭代器遍历增强for遍历Lambda表达式遍历 3.List集合List集合的特有方法List集合的遍历方式五种遍历方式对比 4.数据结构1).栈2).队列3&#xff09;数组4&#xff09;链表小结5&…

【程序员英语】【美语从头学】初级篇(入门)(笔记)Lesson 15 At the Department Store 在百货商店

《美语从头学初级入门篇》 注意&#xff1a;被 删除线 划掉的不一定不正确&#xff0c;只是不是标准答案。 文章目录 Lesson 15 At the Department Store 在百货商店会话A会话B笔记 Lesson 15 At the Department Store 在百货商店 会话A A: Can you help me, please? B: Sur…

世强硬创与SMT激光模板制造商光盛激光达成平台合作

近日&#xff0c;世强先进&#xff08;深圳&#xff09;科技股份有限公司&#xff08;下称“世强先进”&#xff09;与一家专注生产研发电子工业用工模具的企业——东莞光盛激光科技有限公司&#xff08;下称“光盛激光”&#xff09;达成平台合作。 据了解&#xff0c;光盛激光…

Facebook与数字创新:引领社交媒体的数字化革命

在当今数字化时代&#xff0c;社交媒体已经成为了人们日常生活中不可或缺的一部分。而在众多社交媒体平台中&#xff0c;Facebook作为领头羊&#xff0c;一直致力于推动数字创新&#xff0c;引领着社交媒体的数字化革命。本文将探讨Facebook在数字创新方面的表现&#xff0c;以…