Spring Framework中的Bean生命周期

news2025/1/12 20:41:30

目录

一.Bean生命周期的简介

1.基本概念

2.Spring生命周期的几大阶段

3.注意点及小结

 4.生活案例

5.Spring容器管理JavaBean的初始化过程

二. Bean的单例选择与多例选择

1.单例选择与多例选择的优缺点

1.1单例模式的优点:

1.2单例模式的缺点:

1.3多例模式的优点:

1.4多例模式的缺点:

1.5 小结

2.案例演示单例模式与多例模式

1.演示在单例模式和多例模式下资源变量是否被污染

2. 判断单例模式和多例模式的初始化

3.单例模式和多例模式的适用场景


一.Bean生命周期的简介

1.基本概念

Bean生命周期指的是Bean在容器中创建、初始化、使用和销毁的过程。Spring的IoC容器负责管理Bean的生命周期,确保它们按照预期的方式被创建和销毁

2.Spring生命周期的几大阶段

  1. 实例化:在容器启动时,Spring根据配置文件或注解等方式创建Bean的实例。这个阶段是通过调用Bean的构造函数完成的。

  2. 属性注入:在实例化后,Spring会通过各种方式(例如XML配置、注解、Java代码等)将Bean所需的属性值注入到Bean中。可以使用@Autowired@Value等注解来实现依赖注入。

  3. 初始化回调方法:在Bean的所有属性被注入之后,Spring会调用Bean的初始化回调方法。常见的初始化回调方法是实现InitializingBean接口的afterPropertiesSet方法或使用@PostConstruct注解。

  4. 自定义初始化方法:除了使用初始化回调接口和注解外,开发人员还可以在Bean中定义自己的初始化方法。可以通过在Bean的方法上使用@Bean(initMethod = "customInit")注解来指定自定义的初始化方法。

  5. 使用Bean:在初始化后,Bean可以被容器和其他Bean使用。可以在其他Bean中使用依赖注入来获取到已经初始化的Bean。

  6. 销毁回调方法:当容器关闭时或者通过编程方式销毁Bean时,Spring会调用Bean的销毁回调方法。常见的销毁回调方法是实现DisposableBean接口的destroy方法或使用@PreDestroy注解。

  7. 自定义销毁方法:类似于初始化方法,开发人员可以在Bean中定义自己的销毁方法。可以通过在Bean的方法上使用@Bean(destroyMethod = "customDestroy")注解来指定自定义的销毁方法。

3.注意点及小结

当使用Java配置(如@Configuration)时,Bean的生命周期管理通常使用方法级别的@Bean注解,而不是XML配置中的<bean>元素。

总结起来,Spring Bean的生命周期包括实例化、属性注入、初始化回调方法、自定义初始化方法、使用Bean、销毁回调方法和自定义销毁方法。Spring提供了多种方式来管理Bean的生命周期,开发人员可以根据需要选择适合自己的方式

 4.生活案例

假设我们以一个人的生命周期作为生活实例来比喻Spring Bean的生命周期。

  1. 实例化:当一个人出生时,就相当于Bean在容器中被实例化的过程。一个新生婴儿就是一个新的实例,具有独立的身份。

  2. 属性注入:随着时间的推移,这个人会经历各种学习和成长的过程,就像Bean在属性注入阶段接收到不同的属性值。例如,这个人会接受教育、学习技能、掌握知识,这些都是人生中注入的属性。

  3. 初始化回调方法:当这个人成年后,可能会选择一个职业或自己的事业,就像Bean在初始化回调方法阶段定义自己的职责和目标。这个人会明确自己的使命,并准备好开始工作。

  4. 自定义初始化方法:在人生的旅程中,这个人会发展自己的兴趣爱好、价值观和生活方式,就像Bean可以定义自己的初始化方法。这些方法可以帮助这个人构建自己的身份,并适应不同的环境。

  5. 使用:完成初始化后,这个人会活跃在社会中,与其他人交流、工作、合作,就像Bean在容器中被其他组件或应用程序使用。

  6. 销毁回调方法:当一个人的生命接近尾声或者出现一些变故时,他们开始为离开做准备。就像Bean的销毁回调方法一样,这个人可能会处理他们的后事,与亲人和朋友告别,做好最后的安排。

  7. 自定义销毁方法:在离开之前,这个人可以进行一些必要的准备,如写遗嘱、处理财务等,就像Bean可以定义自己的销毁方法来处理必要的清理工作。

通过这个比喻,我们可以将Spring Bean的生命周期与一个人的生命周期进行对比,从而更好地理解Bean在容器中的创建、初始化、使用和销毁的过程。

 

 Bean的生命周期就像我们的一生,人的终点是死亡,Bean的生命周期也一样,终点都是一样的,重要的是过程,所以这里也希望大家能够热爱生活

5.Spring容器管理JavaBean的初始化过程

1.xml/annotation/configuation 配置Javabean

2.BeanDefinitionReader解析配置的JavaBean得到BeanDefinition,最终得到List<BeanDefinition>集合

3.触发BeanFactoryPostProcessor,在Javabean初始化之前执行自己的业务

4.spring中beanFactory,会通过List<BeanDefinition>集合遍历初始化所有的Javabean对象

5.如果自己的JavaBean需要调动Spring上下文中的资源,那么需要实现*aware感知接口

6.如果自己的JavaBean已经初始化好了,还需扩展功能,那么需要借助BeanPostProcessor来实现

二. Bean的单例选择与多例选择

默认状态下Bean的配置的单例的,当然,也可以选择去配置多例的

1.单例选择与多例选择的优缺点

1.1单例模式的优点:

  1. 资源利用:单例模式在应用程序启动时创建一个实例,并一直重用该实例,减少了对象创建和销毁的开销,可以有效利用系统资源。
  2. 全局性:单例模式可以在整个应用程序中共享数据,确保数据的一致性和可靠性。
  3. 状态共享:由于单例只有一个实例,可以方便地在不同的组件之间共享状态,简化了组件之间的通信和数据传递。
  4. 线程安全:单例模式天生具有线程安全的特性,因为只有一个实例在操作,避免了并发访问的问题。

1.2单例模式的缺点:

  1. 资源持有:单例模式的实例会一直存在于内存中,占用一定的系统资源,在某些情况下可能会导致资源浪费。
  2. 生命周期管理:单例模式的实例生命周期长,无法自动释放资源,需要手动管理对象状态和清理资源。
  3. 难以模拟测试:由于单例模式的全局性和状态共享的特性,对于单元测试和模拟测试来说可能会更加困难,因为需要考虑到全局状态的影响。

1.3多例模式的优点:

  1. 灵活性:多例模式可以根据需要创建多个实例,每个实例之间相互独立并具有自己的状态,可以更灵活地应对不同的需求。
  2. 隔离性:多例模式的实例相互独立,不共享状态,可以避免状态污染和互相干扰的问题。
  3. 生命周期管理:每个多例实例的生命周期由Spring容器管理,可以自动释放资源,减少内存泄漏的风险。
  4. 更易于测试:多例模式的实例相互独立,可以更容易地进行单元测试和模拟测试,测试之间不会相互影响。

1.4多例模式的缺点:

  1. 资源占用:多例模式创建了多个实例,会占用更多的内存和系统资源。
  2. 对象管理复杂:多个实例需要由开发者自己管理和控制,需要注意实例的创建、销毁和状态管理,增加了设计和开发的复杂性。
  3. 线程安全:多例模式的实例在并发环境下需要额外考虑线程安全的问题,确保实例之间的数据不会冲突。

1.5 小结

单例模式适用于需要全局共享和状态共享的情况,能够提高资源利用和数据一致性,但需要注意资源管理和生命周期的维护。而多例模式适用于需要灵活性和隔离性的情况,能够减少资源占用和相互影响,但需要开发者自行管理和控制实例的创建和状态。选择单例还是多例取决于具体的业务需求和系统设计的考虑。

2.案例演示单例模式与多例模式

1.演示在单例模式和多例模式下资源变量是否被污染

1.准备好资源

package com.YU.beanlife;

import java.util.List;

import com.YU.ioc.service.UserService;
import com.YU.ioc.service.impl.UserServiceImpl1;
import com.YU.ioc.service.impl.UserServiceImpl2;

public class ParamAction {
	private int age;
	private String name;
	private List<String> hobby;
	private int num = 1;
	// private UserBiz userBiz = new UserBizImpl1();

	public ParamAction() {
		super();
	}

	public ParamAction(int age, String name, List<String> hobby) {
		super();
		this.age = age;
		this.name = name;
		this.hobby = hobby;
	}

	public void execute() {
		// userBiz.upload();
		// userBiz = new UserBizImpl2();
		System.out.println("this.num=" + this.num++);
		System.out.println(this.name);
		System.out.println(this.age);
		System.out.println(this.hobby);
	}
}

2.准备好Bean工厂

package com.YU.beanlife;

public class InstanceFactory {
	public void init() {
		System.out.println("初始化方法");
	}

	public void destroy() {
		System.out.println("销毁方法");
	}

	public void service() {
		System.out.println("业务方法");
	}
}

3.配置xml中的bean目录

<!--spring的生命周期-->
    <bean class="com.YU.beanlife.ParamAction" id="paramAction">
        <constructor-arg name="name" value="死仔"></constructor-arg>
        <constructor-arg name="age" value="21"></constructor-arg>
        <constructor-arg name="hobby">
            <list>
                <value>抽烟</value>
                <value>打go</value>
                <value>烫头</value>
            </list>
        </constructor-arg>
    </bean>
    <bean id="instanceFactory" class="com.YU.beanlife.InstanceFactory"
          scope="prototype" init-method="init" destroy-method="destroy"></bean>

4.编写测试程序

package com.YU.beanlife;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/*
 * spring	bean的生命週期
 * spring	bean的單例多例
 */
public class Demo2 {
	// 体现单例与多例的区别
	@Test
	public void test1() {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
//		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
		ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction");
		ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction");
		// System.out.println(p1==p2);
		p1.execute();
		p2.execute();
		
//		单例时,容器销毁instanceFactory对象也销毁;多例时,容器销毁对象不一定销毁;
		applicationContext.close();
	}

	// 体现单例与多例的初始化的时间点 instanceFactory
	@Test
	public void test2() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
		InstanceFactory instanceFactory = (InstanceFactory) applicationContext.getBean("instanceFactory");

	}

	// BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式
	// 默认情况下bean的初始化,单例模式立马会执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化,只有要获取使用bean对象才进行初始化
	@Test
	public void test3() {
		// ClassPathXmlApplicationContext applicationContext = new
		// ClassPathXmlApplicationContext("/spring-context.xml");

		Resource resource = new ClassPathResource("/spring-context.xml");
		BeanFactory beanFactory = new XmlBeanFactory(resource);
//		InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory");
		
	}

}

其中Test1测试结果为:

由于我们默认使用的是单例模式,所以在运行时出现了变量污染,num值变为2 

当我们配置多例模式同样运行Test1时

scope="prototype"

 运行结果:

由此可得知我们的变量没有被污染 

2. 判断单例模式和多例模式的初始化

配置和上面是一样的

1.当我们运行Test2时测试JavaBean是否跟着初始化

单例模式运行结果:

由单例模式可以看出发生了初始化 

多例模式运行结果:

由此得知并没有出现初始化

当我们用多例模式运行Test3时

运行结果:

 看到红框中的代码,当我们的JavaBean时才会初始化

小结:

由三次运行结果我们可以得出:

1.单例模式中的JavaBean是跟着Spring上下文初始化的,容器生成对象跟着生成,容器死亡,对象死亡

2.多例模式走的Javabean是使用时才会创建,销毁要跟着Jvm走

3.单例模式和多例模式的适用场景

单例模式和多例模式在不同的场景下具有不同的适用性。以下是它们常见的适用场景:

适用于单例模式的场景:

  1. 资源共享:当需要在应用程序的多个组件之间共享同一份资源或数据时,单例模式可以确保全局范围内的数据一致性。
  2. 工厂类:当需要创建一个全局工厂类来统一管理对象的创建和生命周期时,单例模式可以确保该工厂类始终只有一个实例。
  3. 配置信息:当需要在应用程序中加载一份全局的配置信息,并且多个组件需要共享该配置信息时,单例模式可以确保配置信息的一致性和高效访问。
  4. 日志记录器:当需要在整个应用程序中使用同一个日志记录器来记录日志时,单例模式可以确保日志的一致性和集中管理。

适用于多例模式的场景:

  1. 并发请求处理:当需要在多线程或并发环境下处理请求,并且每个请求使用独立的实例来保证状态隔离时,多例模式可以为每个请求创建一个独立的对象。
  2. 对象池:当需要管理一组可复用的对象,并且对象在不同的时刻需要创建和销毁时,多例模式可以提供对象池来管理对象的生命周期,以减少创建和销毁的开销。
  3. 状态管理:当对象的状态需要在不同的上下文环境中独立维护和处理时,多例模式可以为每个上下文环境创建一个独立的实例,以避免状态冲突和相互干扰。
  4. 服务提供者:当系统需要支持多个相同类型的服务提供者,并且每个服务提供者需要独立的实例时,多例模式可以满足服务提供者的创建和管理需求。

注意!!!

单例模式在一些场景下可能存在共享资源竞争、线程安全等问题,需要谨慎设计和考虑并发访问的情况。多例模式在一些场景下可能会增加资源消耗和对象管理的复杂性,需要权衡资源利用和代码复杂度之间的平衡。在实际应用中,根据具体的业务需求和系统设计要求来选择单例模式或多例模式。

 

 很感谢各位大佬的观看,点个关注不迷路,大家的点赞和收藏是博主最大的创作动力,谢谢啦

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

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

相关文章

HC32L110的串口不定长接收及PCA和IRQ的部分问题

show you the code&#xff1a; https://gitee.com/yangfei_addoil/hc32-l110-b6-test 另&#xff1a;程序中使用帕斯卡命名法的是从官方例程上复制的&#xff1b;使用下划线命名法的是博主的&#xff1b; 串口不定长接收 注意串口要自己绑定/指定到一个定时器上&#xff1b…

【仿写tomcat】一、tomcat工作流程

仿写tomcat 简介tomcat简介流程分析tomcat是怎么和访问者交互的&#xff1f;流程图 简介 作者前不久刚仿写了一个简易的tomcat&#xff0c;在此分享给各位&#xff0c;此篇为对tomcat的简介和流程分析&#xff0c;具体仿写内容后续会贴在这里 扫描java文件&#xff0c;获取带…

基于IMX6ULLmini的Linux裸机开发系列六:中断向量表

ARMv7-A 一级查表 等中断真正发生的时候&#xff0c;自动跳转指定位置(基址偏移) 习惯放在代码的起始地方&#xff0c;复位中断放在代码的零地址&#xff0c;被定义的指定中断放在代码的第四个字节的位置 addrTYPEFUNCTIONMODE0x00Reset复位中断SVC0x04Undefined instructi…

Vue-13.创建完整的Vue项目(vue+vue-cli+js)

前言 之前写了命令创建Vue项目&#xff0c;但是事实上我们可以直接用编译器直接创建项目&#xff0c;这里我使用webstorm&#xff08;因为我是前后端兼修的所以我习惯使用Idea家族的编译器&#xff09; 只写前端的推荐用VsCode前后端都写的推荐用webstorm 新建项目 项目初始…

31.Netty源码之客户端启动流程

highlight: arduino-light 客户端启动主要流程 如果看了服务器端的启动流程&#xff0c;这里简单看下就可以了。 java package io.netty.server; ​ import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import …

酒店要如何应对旅游旺季?报修工单管理系统哪家好?

酒店在高峰旅游时期是其最为繁忙的阶段&#xff0c;这时要处理的报修事项比较多&#xff0c;因此应对措施变得尤为重要。填补酒店房间、应对设备故障等情况&#xff0c;造成了来宾数量和压力的急增&#xff0c;因此需要考虑并采用更加有效的安全保障和服务措施&#xff0c;以确…

传输层协议——TCP(上)

文章目录 1. TCP协议1.1 TCP协议段格式1.2 确认应答(ACK)机制1.3 16位窗口大小1.4 6位标志位1.4.1 TCP三次握手 1.5 确认应答(ACK)机制1.6 超时重传机制1.7 连接管理机制1.7.1 理解TIME_WAIT状态1.7.2 理解 CLOSE_WAIT 状态 1. TCP协议 TCP全称为传输控制协议&#xff0c;意思…

Unity 找不到 Navigation 组件的解决

当我们想利用unity 里面的Navigation 组件来实现我们的物体的自动导航时&#xff0c;有时竟然会发现我们的菜单栏里面找不到 该组件 这时我们应该怎么办&#xff1f; 请确保你的项目中已经导入了Unity的AI模块。要导入该模块&#xff0c;请打开"Project Settings"&am…

论文学习——PixelSNAIL:An Improved Autoregressive Geenrative Model

文章目录 引言论文翻译Abstract问题 Introduction第一部分问题 第二部分问题 Model Architecture网络结构第一部分问题第二部分问题 Experiments实验问题 Conclusion结论问题 总结参考 引言 这篇文章&#xff0c;是《PixelSNAIL:An Improved Autoregressive Geenrative Model》…

在自定义数据集上使用 Detectron2 和 PyTorch 进行人脸检测

本文讲讲述如何使用Python在自定义人脸检测数据集上微调预训练的目标检测模型。学习如何为Detectron2和PyTorch准备自定义人脸检测数据集&#xff0c;微调预训练模型以在图像中找到人脸边界。 人脸检测是在图像中找到&#xff08;边界的&#xff09;人脸的任务。这在以下情况下…

STM32F40X系列FSMC8路驱动LCD显示屏(LY-TFT30-39P-1509 芯片hx8352)

hx8352_8080_8bit_FMSC板级驱动 1.LCD相关1.1LCD参数1.2 LCD引脚1.3 LCD实物1.4 LCD引脚解释 2.接线关系3.STM32F40x基于FMSC16bit修改1)地址偏移2)删除多余GPIO3)修改FMSC的配置4&#xff09;LCD初始化寄存器 3.板驱动程序4.运行结果 1.LCD相关 1.1LCD参数 LCD控制芯片&…

C数据结构与算法——无向图(最小生成树) 应用

实验任务 (1) 掌握Kruskal最小生成树算法&#xff1b; (2) 掌握Prim最小生成树算法。 实验内容 (1) 随机生成一个无向网 G ( V, E )&#xff0c;V { A, B, C, D, E, F }&#xff0c;| E | 11&#xff0c;边的权值取值范围为 [ 1, 40 ]&#xff1b; (2) 使用Prim算法求出图…

离散化思想——只处理有效数据的优化思想

离散化思想——只处理有效数据的优化思想 什么是离散化离散化题目——校门外的树&#xff08;超强版&#xff0c;1e9&#xff09;题目描述输入格式输出格式样例样例输入样例输出 提示 思路分析朴素做法离散化&#xff01;&#xff01;代码分析数组循环 什么是离散化 离散化思想…

C语言之浮点数_数据存储篇(2)

目录 浮点数 什么是浮点数呢&#xff1f; 为什么叫浮点数&#xff1f; 浮点数家族 浮点数表示的范围&#xff1f; 浮点数存储的例子 浮点数的存储方式 写成规定形式是怎样的&#xff1f; 那SME在内存中如何分配的呢&#xff1f; 为什么要这样存储&#xff1f; 浮点…

44、TCP报文(二)

接上节内容&#xff0c;本节我们继续TCP报文首部字段含义的学习。上节为止我们学习到“数据偏移”和“保留”字段。接下来我们学习后面的一些字段&#xff08;暂不包含“检验和”的计算方法和选项字段&#xff09;。 TCP首部结构&#xff08;续&#xff09; “数据偏移”和“保…

人工智能在车牌识别中的应用与影响

引言&#xff1a;车牌识别技术是基于人工智能的一种重要应用&#xff0c;通过对监控视频中的车辆图像进行处理和分析&#xff0c;可以快速、准确地识别车牌号码。这项技术的广泛应用可以帮助交通管理、停车场管理&#xff0c;甚至追踪犯罪嫌疑人的车辆。本文将详细探讨车牌识别…

从LeakCanary看ViewModel生命周期监控

前面两篇文章中已经了解了LeakCanary中Service和Fragment生命周期监控的实现&#xff0c;那么ViewModel生命周期监控又是怎么实现的呢&#xff1f; 同样的&#xff0c;要了解ViewModel生命周期监控&#xff0c;我们首先应该清楚在代码结构中ViewModel是如何存储获取的&#xf…

【零基础自用】理解python为什么要用虚拟环境

不知道学过MATLAB或者R的小伙伴刚刚接触python的时候会不会被各种python版本&#xff0c;包版本&#xff0c;虚拟环境之类的搞的头晕眼花。 问题一 包版本 先来假设&#xff0c;我们自己开发了一个包MyPackage 1.0&#xff0c;里面包含一个模块叫PreTrained&#xff0c;然后去…

Python爬虫(十三)_案例:使用XPath的爬虫

本篇是使用XPath的案例 案例&#xff1a;使用XPath的爬虫 现在我们用XPath来做一个简单的爬虫&#xff0c;我们尝试爬取某个贴吧里的所有帖子且将该帖子里每个楼层发布的图片下载到本地。 #-*- coding:utf-8 -*- #tieba_xpath.py"""作用&#xff1a;本案例使用…

【AGC】Publishing api怎么上传绿色认证审核材料

【问题描述】 华为应用市场会对绿色应用标上特有的绿色标识&#xff0c;代表其通过华为终端开放实验室DevEco云测平台的兼容性、稳定性、安全、功耗和性能的检测和认证&#xff0c;是应用高品质的象征。想要自己的应用认证为绿色应用就需要在发布应用时提供绿色认证审核材料&a…