【spring】Bean的生命周期回调函数和Bean的循环依赖

news2025/1/12 9:58:37

目录

1、Bean的生命周期

2、Bean的生命周期回调函数 

2.1、初始化的生命周期回调

2.2、销毁的生命周期回调

3、Bean的循环依赖

1、Bean的生命周期

        spring的bean的生命周期主要是创建bean的过程,一个bean的生命周期主要是4个步骤:实例化,属性注入,初始化,销毁

再详细一点可以拆分为:

(1)配置bean,通过@Component @Bean等方式都可以。

(2)加载Spring容器

(3)实例化,例如:(BeanService beanService = new BeanService())

(4)解析依赖注入(解析@Autowired @Value等自动注入注解)

(5)初始化(调用初始化回调方法,由程序员来配置)

(6)最终放入一个Map集合,Map<beanName, bean对象>

(7)spring容器.getBean("beanName")---->Map<beanName, bean对象>

(8)spring容器关闭 bean就会销毁(调用销毁回调方法,由程序员来配置)

2、Bean的生命周期回调函数 

2.1、初始化的生命周期回调

初始化(调用初始化回调方法,由程序员来配置),有三种方式来配置初始化回调方法

示例:

//自定义类LtService
public class LtService implements InitializingBean {

    // 基于接口实现初始化回调方法,重写了InitializingBean接口中的afterPropertiesSet()方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("接口:初始化");//接口实现初始化回调方法
    }

    // 基于注解实现初始化回调方法
    @PostConstruct
    public void init() throws Exception {
        System.out.println("注解@PostConstruct:初始化");//注解@PostConstruct实现初始化回调方法
    }

    // 基于initMethod属性实现初始化回调方法
    public void init2() throws Exception {
        System.out.println("initMethod属性:初始化");//initMethod属性实现初始化回调方法
    }
}


//测试类LifeCallbackTest
@SpringBootTest(classes = LifeCallbackTest.class)
public class LifeCallbackTest {

    //通过@Bean的方式把LtService配置成bean
    @Bean(initMethod = "init2")
    public LtService ltService(){
        return new LtService();
    }

    @Test
    public void test(@Autowired LtService ltService){
        System.out.println(ltService.getClass());
    }
}

从上面的结果可以看出他们的顺序是:先注解,再接口,最后initMethod属性

小补充:

2.2、销毁的生命周期回调

1.在springboot中当jvm进程结束后会自动调用容器.close0),自动销毁bean

2.在spring中,需要手动调用容器.close()来销毁bean

销毁(调用销毁回调方法,由程序员来配置),有三种方式来配置销毁回调方法

示例:

//自定义类LtService
//public class LtService implements InitializingBean , DisposableBean {
public class LtService implements DisposableBean {

    // 基于接口实现销毁回调方法,重写了DisposableBean接口中的destroy()方法
    @Override
    public void destroy() throws Exception {
        System.out.println("接口:销毁");//接口实现销毁回调方法
    }

    // 基于注解实现销毁回调方法
    @PreDestroy
    public void destroy2() throws Exception {
        System.out.println("注解@PreDestroy:销毁");//注解@PreDestroy实现销毁回调方法
    }

    // 基于destroyMethod属性实现销毁回调方法
    @PostConstruct
    public void destroy3() throws Exception {
        System.out.println("destroyMethod属性:初始化");//destroyMethod属性实现销毁回调方法
    }
}


//测试类
@SpringBootTest(classes = LifeCallbackTest.class)
public class LifeCallbackTest {

    //@Bean(initMethod = "init2", destroyMethod = "destroy3")
    @Bean(destroyMethod = "destroy3")
    public LtService ltService(){
        return new LtService();
    }

    @Test
    public void test(@Autowired LtService ltService){
        System.out.println(ltService.getClass());
    }
}

从上面的结果可以看出他们的顺序是:先注解,再接口,最后destroyMethod属性

3、Bean的循环依赖

        循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于A。如下图:

        注意,这里不是函数的循环调用,是对象的相互依赖关系。循环调用其实就是一个死循环,除非有终结条件。

        Spring已经帮我们解决了循环依赖这个问题,这涉及到Spring底层源码的概念(Spring怎么解决的循环依赖)。但是,在SpringBoot中会报错,因为SpringBoot认为是一种不合理的设计

循环依赖在SpringBoot中会报错的解决方式:

1、在配置文件中放开循环依赖的限制

#放开循环依赖的限制
spring.main.allow-circular-references=true

2、代码设计层面:

a.把依赖的方法,直接写在本类中

b.添加一个中间类, 中间类去依赖A\B,然后让中间类去阻止他们的依赖方法

3、延迟注入

a.添加需要依赖的构造函数参数

b.添加@Lazy注解

@Lazy
public BeanA(BeanB beanb){
    this.beanb = beanb;
}

@Lazy
public Bean(BeanA beana){
    this.beana = beana;
}

推荐: 

【Spring】IOC/DI中常用的注解@Lazy、@Scope与@Conditional-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/138277932?spm=1001.2014.3001.5501【Spring】IOC/DI中常用的注解@Order与@DependsOn-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/138167160?spm=1001.2014.3001.5501【Spring】依赖注入(DI)时常用的注解@Autowired和@Value_配置类 使用@autowired 类型注入-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/137784706?spm=1001.2014.3001.5501

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

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

相关文章

【属性系统概述】

属性系统概述 &#x1f31f; 静态属性与动态属性&#x1f31f; 官方文档中的定义&#x1f31f;《Qt 5.9 C开发指南》中的定义&#x1f31f; Qt中属性的使用 &#x1f31f; 静态属性与动态属性 ✨ 静态属性 &#xff1a;在创建QObject类时通过宏Q_PROPERTY定义的属性&#xff0c…

让GPT们成为我们的小助手:使用ChatGPT来生成测试用数据

让GPT们成为我们的小助手 任务&#xff1a;帮忙生成测试数据 今天本来想做一个测试&#xff0c;所以需要一些测试数据。为了让测试显得更真实&#xff0c;所以希望测试数据看上去就是一份真实的数据&#xff0c;所以我就希望ChatGPT&#xff08;这里是代指&#xff0c;我有使…

vue3对象数组格式的动态表单校验

如你有一个表单&#xff0c;表单内容是对象&#xff0c;但是对象内还有可动态循环的数组进行动态表单校验。 效果如图&#xff1a;查看源码 页面内容&#xff1a; <div class"arrForm-Box"><el-form :model"state.formData" :rules"rule…

基于springboot+vue+Mysql的体质测试数据分析及可视化设计

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Oracle count的优化-避免全表扫描

Oracle count的优化-避免全表扫描 select count(*) from t1; 这句话比较简单&#xff0c;但很有玄机&#xff01;对这句话运行的理解&#xff0c;反映了你对数据库的理解深度&#xff01; 建立实验的大表他t1 SQL> conn scott/tiger 已连接。 SQL> drop table t1 purge…

OpenAI 正在开发一种可以防止版权诉讼的工具

OpenAI 正在开发一种名为 Media Manager 的工具&#xff0c;该工具将使内容创建者和所有者能够确定他们是否愿意将自己的内容用于 ML 研究和 AI 模型训练。 Media Manager 将做什么&#xff1f; 明年推出的 Media Manager 将使内容创作者和所有者能够更好地控制他们的工作是否…

Java学习第05天-编程思维与编程能力

文章目录 综合应用案例&#xff1a;找素数数组元素的复制数字加密模拟双色球 综合应用 涉及的知识点&#xff1a; 变量、数组运算符&#xff1a;基本运算符、关系运算符、逻辑运算符流程控制&#xff1a;if、switch、for、while、死循环、循环嵌套跳转关键字&#xff1a;break、…

day5Qt作业

服务器端 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//准备组件&#xff0c;初始化组件状态this->setFixedSize(800,600);chatwidget new QListWidge…

Box86源码解读记录

1. 背景说明 Github地址&#xff1a;https://github.com/ptitSeb/box86 官方推荐的视频教程&#xff1a;Box86/Box64视频教程网盘 2. 程序执行主体图 Box86版本: Box86 with Dynarec v0.3.4 主函数会执行一大堆的初始化工作&#xff0c;包括但不限于&#xff1a;BOX上下文 …

三层交换机静态路由连通实验

静态路由是一种手动配置路由表的方式&#xff0c;网络管理员需要手动指定网络中的每一个路由器下一跳路由器的地址&#xff0c;以及到达目的网络的最短路径。静态路由的路由表不会自动更新&#xff0c;如果网络拓扑发生了变化&#xff0c;管理员需要手动更改路由表。 实验拓扑图…

信息系统架构模型_1.单机应用模式和客户机/服务器模式

1.单机应用模式&#xff08;Standalone&#xff09; 单机应用系统是最简单的软件结构&#xff0c;是指运行在一台物理机器上的独立应用程序。这些软件系统&#xff0c;从今天的软件架构上来讲&#xff0c;是很简单&#xff0c;是标准的单机系统。当然至今&#xff0c;这种复杂的…

面向对象 03:类与对象的创建、初始化和使用,通过 new 关键字调用构造方法,以及创建对象过程的内存分析

一、前言 记录时间 [2024-05-10] 系列文章简摘&#xff1a; Java 笔记 01&#xff1a;Java 概述&#xff0c;MarkDown 常用语法整理 Java 笔记 11&#xff1a;Java 方法相关内容&#xff0c;方法的设计原则&#xff0c;以及方法的定义和调用 面向对象 01&#xff1a;Java 面向对…

数学:人工智能领域的基石与灵魂

在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到了我们生活的方方面面&#xff0c;从智能家居、智能医疗到自动驾驶、智能客服&#xff0c;AI无处不在。然而&#xff0c;当我们赞叹于AI的神奇时&#xff0c;却往往忽视了其背后的推动力——数学…

Leetcode—2105. 给植物浇水 II【中等】

2024每日刷题&#xff08;131&#xff09; Leetcode—2105. 给植物浇水 II 实现代码 class Solution { public:int minimumRefill(vector<int>& plants, int capacityA, int capacityB) {int size plants.size();int i 0;int j size - 1;int capA capacityA;in…

结合创新!通道注意力+UNet,实现高精度分割

在U-Net网络中加入通道注意力机制能显著提升模型的性能&#xff01; 具体点说是在U-Net的卷积层之后添加一个通道注意力模块&#xff0c;这样这个模块可以学习不同通道之间的权重&#xff0c;并根据这些权重对通道进行加权&#xff0c;从而增强重要通道的特征表示。 这种结合…

【WebGIS实例】(14)MapboxGL 加载地形高程数据

前言 官网示例&#xff1a;Add 3D terrain to a map | Mapbox GL JS | Mapbox 大佬博客&#xff1a;Mapbox GL基础&#xff08;七&#xff09;&#xff1a;地形数据的处理与加载 (jl1mall.com) 加载Mapbox地形数据 map.once(style.load, () > {map.addSource(mapbox-dem,…

常见扩频系统的基础概念和模型

扩频系统是一种通信技术&#xff0c;它通过将信号的频谱扩展到一定程度来实现传输&#xff0c;这种系统的设计和实现涉及到多种不同的方法和技术。 扩频系统的主要特点和好处包括&#xff1a; 抗干扰能力强&#xff1a;由于信号被扩展到较宽的频带上&#xff0c;单位带宽内的功…

代码随想录算法训练营第六十二天|503.下一个更大元素II、42.接雨水

代码随想录算法训练营第六十二天|503.下一个更大元素II、42.接雨水 503.下一个更大元素II 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元…

jenkins使用gitLab(极狐)认证登陆

jenkins安装 GitLab Authentication插件 我因为java版本和最新GitLab Authentication 1.19版本不兼容&#xff0c;选择了本地安装 找个历史版本1.13版本&#xff0c;然后下载到电脑上 - 本地上传插件并安装 在极狐上创建一个应用 - 配置应用信息 应用名&#xff1a;jenkinsLo…

GAMMA Lab——知识图谱和LLM大模型

图机器学习的发展与分类 图基础模型 LLM基础模型 GNN LLM 前沿工作