【JavaEE】Bean的作用域和生命周期

一.Bean的作用域.

1.1 Bean的相关概念.

  • 通过Spring IoC和DI的学习(不清楚的可以看的前面写过的总结,可以快速入门, http://t.csdnimg.cn/K8Xr0),我们知道了Spring是如何帮助我们管理对象的

      1. 通过 @Controller , @Service , @Repository , @Component , @Configuration ,
        @Bean 来声明Bean对象.
      1. 通过 ApplicationContext 或者 BeanFactory 来获取对象
      1. 通过 @Autowired , Setter 方法或者构造方法等来为应用程序注入所依赖的Bean对象
  • 通过代码来演示回顾一下:
    创建需要注入的对象

public class Dog {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

把这个对象进行实例化,并且交给Spring进行管理

@Configuration
public class DogConfig {@Beanpublic Dog dog() {Dog dog = new Dog();dog.setName("旺财");return dog;}
}

通过ApplicationContext来获取对象.

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class SpringPrincipleApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(com.tuanzi.springprinciple.SpringPrincipleApplication.class, args);Dog bean = context.getBean(Dog.class);System.out.println(bean.getName());}
}

在这里插入图片描述
也可以通过在代码中直接注入ApplicationContext的方式来获取Spring容器

@SpringBootTest
class SpringPrincipleApplicationTests {@Autowiredpublic ApplicationContext context;@Testvoid contextLoads() {Dog bean1 = context.getBean("dog", Dog.class);System.out.println(bean1);Dog bean2 = context.getBean("dog", Dog.class);System.out.println(bean2);}
}

在这里插入图片描述

根据运行结果我们可以看出, 这两次获取的对象是同一个对象, 默认情况下从Spring容器中取出来的对象是同一个

  • 默认情况下, Spring容器中的bean都是单例的, 这种行为模式, 我们就称之为Bean的作用域

二.Bean的作用域

2.1 七种Bean的作用域

  • Bean的作用域定义了Bean实例的生命周期及其在Spring容器中的可见性。
  • 在Spring中支持6中作用域, 后四种在MVC环境下才能生效:
名称作用域说明
单例作用域singleton每个Spring IoC容器内同名称的Bean只有一个实例(单例) 默认情况
原型作用域prototype每次使用该Bean的时侯,都会创建新的实例
请求作用域request每个HTTP请求都会创建一个新的Bean实例,请求结束时销毁
会话作用域session每个HTTP会话都会创建一个新的Bean实例,会话结束时销毁
全局作用域Application在ServletContext范围内,整个Web应用程序共享同一个Bean实例
HTTP WebSocket作用域websocket在ServletContext范围内,整个Web应用程序共享同一个Bean实例
全局作用域Application一个Bean定义对应于单个websocket的生命周期,仅在WebApplicationContext环境中有效
自定义作用域custom除了以上六种标准作用域,Spring还允许开发人员创建自定义作用域,通过实现Scope接口并注册到Spring容器中

参考文档: https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html

2.2 代码演示.

2.2.1 单例作用域(singleton)

@Configuration
public class DogConfig {@Bean@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)public Dog singletonDog() {return new Dog();}
}
@RestController
public class DogController {@Autowiredprivate ApplicationContext applicationContext;@Autowiredprivate Dog singletonDog;@RequestMapping("/single")public String single(){Dog contextDog = applicationContext.getBean("singletonDog", Dog.class);return "contextDog = " + contextDog+", "+"autowiredDog = " + singletonDog;}

观察Bean的作用域. 单例作⽤域: http://127.0.0.1:8080/single
多次访问, 得到的都是同⼀个对象, 并且 @Autowired 和 applicationContext.getBean()
也是同⼀个对象
在这里插入图片描述

2.2.2 原型作用域( prototype)

	@Bean@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)public Dog prototypeDog() {return new Dog();}
	@Autowiredprivate Dog prototypeDog;@RequestMapping("/prototype")public String prototype(){Dog contextDog = applicationContext.getBean("prototypeDog", Dog.class);return "contextDog = " + contextDog+", "+"autowiredDog = " + prototypeDog;}

多例作用域: http://127.0.0.1:8080/prototype
观察ContextDog, 每次获取的对象都不一样==(注入的对象在Spring容器启动时, 就已经注入了, 所以多次请求也不会发生变化==)
在这里插入图片描述
在这里插入图片描述

2.2.3 请求作用域(request)

	@Bean@RequestScopepublic Dog requestDog() {return new Dog();}
	@Autowiredprivate Dog requestDog;@RequestMapping("/request")public String request(){Dog contextDog = applicationContext.getBean("requestDog", Dog.class);return "contextDog = " + contextDog+", autowiredDog = " + requestDog;}

请求作用域: http://127.0.0.1:8080/request
在一次请求中, @Autowired 和 applicationContext.getBean() 也是同一个对象.但是每次请求(刷新浏览器当前页面), 都会重新创建对象.
在这里插入图片描述
在这里插入图片描述

2.2.4 会话作用域(session)

	@Bean@SessionScopepublic Dog sessionDog() {return new Dog();}
	@Autowiredprivate Dog sessionDog;@RequestMapping("/session")public String session(){Dog contextDog = applicationContext.getBean("sessionDog", Dog.class);return "contextDog = " + contextDog+", autowiredDog = " + sessionDog;}

在一个session中, 多次请求, 获取到的对象都是同一个, 换一个浏览器访问, 发现会重新创建对象.(另一个Session)
Google浏览器运行结果:
在这里插入图片描述
Edge浏览器运行结果:
在这里插入图片描述

2.2.5 Application(全局作用域)

	@Bean@ApplicationScopepublic Dog applicationDog() {return new Dog();}
	@Autowiredprivate Dog applicationDog;@RequestMapping("/application")public String application(){Dog contextDog = applicationContext.getBean("applicationDog", Dog.class);return "contextDog = " + contextDog+", autowiredDog = " + applicationDog;}

在一个应用中, 多次访问都是同一个对象(不同的浏览器也是同一个对象).
Application scope就是对于整个web容器来说, bean的作⽤域是ServletContext级别的. 这个和
singleton有点类似,==区别在于: Application scope是ServletContext的单例, singleton是⼀个
ApplicationContext的单例. 在⼀个web容器中ApplicationContext可以有多个. ==
Google浏览器运行结果:
在这里插入图片描述
Edge浏览器运行结果:
在这里插入图片描述

三.Bean的生命周期.

3.1 基本概念

  • 生命周期指的是一个对象从诞生到销毁的整个生命过程, 我们把这个过程就叫做一个对象的生命周期.
  • Bean 的生命周期分为以下5个部分:
    • 1.实例化(为Bean分配内存空间)
    • 2.属性赋值(Bean注入和装配, 比如 @AutoWired )
    • 3.初始化
      • a. 执行各种通知, 如 BeanNameAware , BeanFactoryAware ,ApplicationContextAware 的接口方法.
      • b. 执行初始化方法
        • xml定义 init-method
        • 使用注解的方式 @PostConstruct
        • 执行初始化后置方法( BeanPostProcessor )
      1. 使用Bean
      1. 销毁Bean
      • a. 销毁容器的各种方法, 如 @PreDestroy , DisposableBean 接口方法, destroy method.

实例化和属性赋值对应构造⽅法和setter⽅法的注⼊. 初始化和销毁是⽤⼾能⾃定义扩展的两个阶段,
可以在实例化之后, 类加载完成之前进⾏⾃定义"事件"处理.
⽐如我们现在需要买⼀栋房⼦, 那么我们的流程是这样的:

  1. 先买房(实例化, 从⽆到有)
  2. 装修(设置属性)
  3. 买家电, 如洗⾐机, 冰箱, 电视, 空调等([各种]初始化,可以⼊住);
  4. ⼊住(使⽤ Bean)
  5. 卖房(Bean 销毁)
  • 执⾏流程如下图所⽰:
    在这里插入图片描述

3.2 代码实现.

@Component
public class BeanLifeComponent implements BeanNameAware {private Dog singletonDog;public BeanLifeComponent() {System.out.println("执行构造函数....");}@Autowiredpublic void setSingletonDog(Dog singletonDog) {this.singletonDog = singletonDog;System.out.println("执行了setSingletonDog");}@Overridepublic void setBeanName(String name) {System.out.println("setBeanName"+name);}@PostConstructpublic void init() {System.out.println("执行PostConstruct方法");}public void use(){System.out.println("执行use方法");}@PreDestroypublic void destroy(){System.out.println("执行destroy");}
}

执行结果:
在这里插入图片描述
通过运行结果观察

  1. 先执行构造函数
  2. 设置属性
  3. Bean初始化
  4. 使用Bean
  5. 销毁Bean

3.3 生命周期的源码阅读.

  • 创建Bean的代码入口在 AbstractAutowireCapableBeanFactory#createBean

== 点进去继续看源码: AbstractAutowireCapableBeanFactory#createBean ==

//---------------------------------------------------------------------// Implementation of relevant AbstractBeanFactory template methods//---------------------------------------------------------------------/*** Central method of this class: creates a bean instance,* populates the bean instance, applies post-processors, etc.* @see #doCreateBean*/@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

三方法与三个生命周期阶段一一对应

  1. createBeanInstance() -> 实例化
  2. populateBean() -> 属性赋值
  3. initializeBean() -> 初始化

继续点进去 initializeBean

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {invokeAwareMethods(beanName, bean);Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);}if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}private void invokeAwareMethods(String beanName, Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware beanNameAware) {beanNameAware.setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {beanClassLoaderAware.setBeanClassLoader(bcl);}}if (bean instanceof BeanFactoryAware beanFactoryAware) {beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}}

可以看到,调用了三个Bean开头的Aware方法.

四. 总结

  1. Bean的作用域共分为6种: singleton, prototype, request, session, application和websocket.
  2. Bean的生命周期共分为5大部分: 实例化, 属性复制, 初始化, 使用和销毁

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

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

相关文章

无人机之航拍高级操作与技巧

一、直线飞行与矩形飞行练习&#xff1a;通过直线和矩形路径的练习&#xff0c;提升飞行路径控制能力。 二、航点命令和事件编程&#xff1a;学习如何设置航点命令和事件&#xff0c;使无人机能够自动执行复杂任务。 三、故障诊断与处理&#xff1a;掌握基本的故障诊断方法和…

如何使用 API list 极狐GitLab 群组中的镜像仓库?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

深入指南:VitePress 如何自定义样式

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

PHP安全编程宝典:30000字精细解析

文章目录 基础语法单双引号的区别前后端分离数据类型PHP常量函数var_dump函数count函数print_r函数**readfile&#xff08;&#xff09;函数****file_get_contents()函数****file_put_contents()函数**header函数fopen函数fread 函数rename函数copy&#xff08;&#xff09;函数…

【时时三省】(C语言基础)结构体

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ——csdn时时三省 结构体 结构体使得C语言有能力描述复杂类型。 结构体可以让c语言创造新的类型出来 示例: struct Stu &#xff5b; char name&#xff3b;20&#xff3d; &#xff08;名字的话是一个字…

数学建模--简单优化模型之存储模型

目录 1.问题概述 1.1问题介绍 1.2优化目标 2.问题的分析与思考 2.1已知条件的说明 2.2正确的理解准备费 2.3三个举例 3.模型的假设 4.模型的建立与求解 4.1模型的建立 4.2模型的求解 5.灵敏度分析 6.模型推广 1.问题概述 1.1问题介绍 上面这个已经介绍了&#xff…

web小项目-曼波生日录(Servlet+JSP+MySQL)

效果演示&#xff1a; 当记录条数过多时会自动出现滚轮&#xff0c;数据不会超出紫框 数据库实时记录&#xff1a; 项目源代码以及所用到的资源&#xff1a; 链接: https://pan.baidu.com/s/1w0czmH9xBfetk7CZ7RNbtQ?pwd6666 提取码: 6666 复制这段内容后打开百度网盘手机App…

PaddleOCR-PP-OCRv4推理详解及部署实现(下)

目录 前言1. 检测模型1.1 预处理1.2 后处理1.3 推理 2. 方向分类器模型2.1 预处理2.2 后处理2.3 推理 3. 识别模型3.1 预处理3.2 后处理3.3 推理 4. PP-OCRv4部署4.1 源码下载4.2 环境配置4.2.1 配置CMakeLists.txt4.2.2 配置Makefile 4.3 ONNX导出4.4 engine生成4.4.1 检测模型…

linux进程——解析命令行参数——环境变量详解

前言&#xff1a;本节内容还是linux进程&#xff0c; 主要讲解里面的环境变量——我们首先要知道的就是环境变量其实就是操作系统维护的一组kv值&#xff0c; 环境变量是系统提供的一组 变量名变量值 形式的变量。不同的环境变量之间具有不同的用途&#xff0c; 并且具有全局属…

(雷达数据处理中的)跟踪算法(4) --- 基于数据集的目标跟踪实践

说明 本文作为跟踪系列的第4篇博文&#xff0c;在前面几篇博文[1][2][3]的基础上对所采集的实际数据(来自国防科技大学电子科学学院所主导发布的数据集[4])进行跟踪实践。读者在阅读本文前&#xff0c;建议先阅读本系列的前3篇博文。 Blog 20240724 博文第一次撰写 目录 说明…

【Linux】管道通信和 system V 通信

文章目录 一、进程通信原理&#xff08;让不同进程看到同一份资源&#xff09;二、管道通信2.1 管道原理及其特点2.1 匿名管道和命名管道 三、共享内存通信3.1 共享内存原理3.2 创建和关联共享内存3.3 去关联、ipc 指令和删除共享内存 四、消息队列和信号量&#xff08;了解&am…

【Unity2D 2022:UI】无法拖拽TextMeshPro组件

在预制体Card上挂载了四个Text Mesh Pro组件&#xff0c;分别命名为Name、HP、ATK、Description。 将预制体Card挂载脚本CardDisplay用来在预制体上显示属性&#xff0c;并创建TextMeshPro对象来接收TextMeshPro组件。 using TMPro; using UnityEngine; using UnityEngine.UI;…

HCIP之PPP协议(PAP认证,CHAP认证)、GRE、MGRE综合实验

实验过程 一、IP配置 [r1]interface Serial 4/0/0 [r1-Serial4/0/0]ip ad 15.1.1.1 24 [r1]interface GigabitEthernet 0/0/0 [r1-GigabitEthernet0/0/0]ip ad 192.168.1.1 24 r2]interface Serial 4/0/0 [r2-Serial4/0/0]ip ad 25.1.1.2 24 [r2]interface GigabitEthernet 0/…

基于 HTML+ECharts 实现智慧交通数据可视化大屏(含源码)

构建智慧交通数据可视化大屏&#xff1a;基于 HTML 和 ECharts 的实现 随着城市化进程的加快&#xff0c;智慧交通系统已成为提升城市管理效率和居民生活质量的关键。通过数据可视化&#xff0c;交通管理部门可以实时监控交通流量、事故发生率、道路状况等关键指标&#xff0c;…

LabVIEW多种测试仪器集成控制系统

在现代工业生产与科研领域&#xff0c;对测试设备的需求日益增长。传统的手动操作测试不仅效率低下&#xff0c;而且易出错。本项目通过集成控制系统&#xff0c;实现了自动化控制&#xff0c;降低操作复杂度和错误率&#xff0c;提高生产和研究效率。 系统组成与硬件选择 系…

MSSQL注入前置知识

简述 Microsoft SQL server也叫SQL server / MSSQL&#xff0c;由微软推出的关系型数据库&#xff0c;默认端口1433 常见搭配C# / .net IISmssql mssql的数据库文件 数据文件&#xff08;.mdf&#xff09;&#xff1a;主要的数据文件&#xff0c;包含数据表中的数据和对象信息…

Mongodb入门介绍

文章目录 1、Mongodb&#xff1a;NoSQL数据库&#xff0c;分布式的文档型数据库2、适合场景&#xff1a;3、不适合场景&#xff1a;4、概念5、总结 1、Mongodb&#xff1a;NoSQL数据库&#xff0c;分布式的文档型数据库 2、适合场景&#xff1a; 1、web网站数据存储&#xff…

鸿蒙 Navigation VS Router 对比

当前HarmonyOS支持两套路由机制&#xff08;Navigation和Router&#xff09;&#xff0c;Navigation作为后续长期演进及推荐的路由选择方案&#xff0c;其与Router比较的优势如下&#xff1a; 易用性层面&#xff1a; Navigation天然具备标题、内容、回退按钮的功能联动&…

Springboot循环依赖的解决方式

Springboot循环依赖的解决方式 起因原因解决方案配置文件解决使用工具类获取bean还有一种我设想的方案 起因 今天重构代码时&#xff0c;发现之前的代码结构完全混乱&#xff0c;没有按照MVC分层思想去编写&#xff0c;很多业务逻辑写在了controller中&#xff0c;导致引用的很…

Java | Leetcode Java题解之第278题第一个错误的版本

题目&#xff1a; 题解&#xff1a; public class Solution extends VersionControl {public int firstBadVersion(int n) {int left 1, right n;while (left < right) { // 循环直至区间左右端点相同int mid left (right - left) / 2; // 防止计算时溢出if (isBadVers…