bean的作用域和生命周期和后置处理器以及作用域对生命周期的影响~

news/2024/3/29 10:10:10/文章来源:https://blog.csdn.net/m0_64365419/article/details/129665234

scope属性可以指定bean的作用范围:

在spring中可以通过配置bean标签的scope属性来指定bean的作用域范围,各取值含义参照表如下:

在这里插入图片描述

编写spring_test.xml文件:

<?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">
<bean id="student_one" class="poij.student"><property name="sid" value="101"></property><property name="sname" value="张三"></property><property name="age" value="19"></property><property name="gender" value=""></property>
</bean>
</beans>

编写其中的测试类:

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import poij.student;public class scope_test {@Testpublic void scopeText(){ApplicationContext ioc=new ClassPathXmlApplicationContext("spring-scope.xml");student student1=ioc.getBean(student.class);student student2=ioc.getBean(student.class);//通过比较student1和student2是否为同一个进而判断bean对象是否为单例System.out.println(student1.equals(student2));}
}

输出:

true

在本例测试中,我们并没有设置scope属性的值,它与设置scope=“singleton”,所输出结果是一样的,都是表示获取该bean所对应的对象都是同一个

设置scope属性的值是prototype,表示获取该bean所对应的对象都不是同一个

<bean id="student_one" class="poij.student" scope="prototype">

再次进行测试,输出结果如下所示;

false

bean的生命周期:

bean对象创建(调用无参构造)
给bean对象设置属性
bean对象初始化之前操作(由bean的后置处理器负责)
bean对象初始化(需要在配置bean时指定初始化方法)
bean对象初始化之后操作(由bean的后置处理器负责)
bean对象就绪可以使用
bean对象销毁(需要在配置bean时,指定销毁方法)
IOC容器关闭

创建实体类user:

package projo;public class User {private String username;private  Integer id;private  String password;private  Integer age;public String getUsername() {return username;}public Integer getId() {return id;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public void setId(Integer id) {System.out.println("生命周期2:依赖注入");this.id = id;}public void setUsername(String username) {this.username = username;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public User() {System.out.println("生命周期1:实例化");}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", id=" + id +", password='" + password + '\'' +", age=" + age +'}';}public User(int id,String username,String password,int age) {this.age=age;this.password=password;this.id=id;this.username = username;}//创建初始化的过程public void initMethod(){System.out.println("生命周期3:初始化");}//创建销毁的过程public void destroyMethod(){System.out.println("生命周期4:销毁");}
}

spring_lifecycle.xml:

<?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"><bean id="user" class="projo.User"><property name="id" value="1"></property><property name="username" value="张三"></property><property name="password" value="124"></property><property name="age" value="16"></property></bean>
</beans>

创建测试类:

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import projo.User;public class lifecycle {@Testpublic void test(){ApplicationContext ioc=new ClassPathXmlApplicationContext("spring_lifecycle.xml");User user=ioc.getBean(User.class);System.out.println(user);}
}

输出:

生命周期1:实例化
生命周期2:依赖注入
User{username='张三', id=1, password='124', age=16}

我们在User类中,不仅创建了生命周期,而且还创建了销毁和初始化的方法,但是在输出结果中,销毁和初始化方法中的内容并没有输出,原因是:如果我们想要调用初始化和销毁的方法,需要在spring.xml文件中通过bean标签中的init-method和destory-method属性指定的,如下所示:

<bean id="user" class="projo.User" init-method="initMethod" destroy-method="destroyMethod">

再次测试,输出结果如下所示:

生命周期1:实例化
生命周期2:依赖注入
生命周期3:初始化
User{username='张三', id=1, password='124', age=16}

此时的初始化方法被调用了,但销毁方法为什么依然没调用呢?

那么销毁的方法什么时候才会执行呢?我们知道bean对象都是通过IOC容器创建和管理的,那么一旦IOC容器关闭就意味着对象被销毁了

那么容器怎么关闭呢?之前在java中我们都是通过调用close方法区关闭资源,那么这里也可以吗?

一试便知,如下所示,当我们尝试调用close方法想要关闭IOC容器时,却发现没有这个方法

在这里插入图片描述

原因是:ApplicationContext类中并没有提供刷新或者关闭容器的功能,而其功能是在子接口[ConfigurableApplicationContext]中提供的

解决方案:

将ApplicationContext类修改为ConfigurableApplicationContext

import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import projo.User;public class lifecycle {@Testpublic void test(){//获取IOC容器ConfigurableApplicationContext  ioc=new ClassPathXmlApplicationContext("spring_lifecycle.xml");//获取beanUser user=ioc.getBean(User.class);//输出beanSystem.out.println(user);//关闭IOCioc.close();//关闭容器}
}

输出如下所示:

当容器关闭时,对象被成功销毁

生命周期1:实例化
生命周期2:依赖注入
生命周期3:初始化
User{username='张三', id=1, password='124', age=16}
生命周期4:销毁

bean的作用域对生命周期的影响:

对上述的lifecycle类中,我们只保留获取IOC容器的代码,那么会输出什么?

输出如下所示:

生命周期1:实例化
生命周期2:依赖注入
生命周期3:初始化

通过输出结果我们会发现,生命周期的前三个方法是在获取IOC容器时,就执行的,并不是我们在获取bean时,才执行的,原因是,我们当前在IOC容器中配置的bean对象,默认是单例,那么就说明,我们根据这个IOC容器获取到的永远都是一个唯一的bean对象那么我们根本没必要在获取的时候再去创建它,直接在创建IOC容器的时候就将其创建好,以后使用的都是同一个

既然是与单例还是多例有关,那么如果我们在bean标签中将其设置为多例,bean对象的创建还能否在获取IOC容器时就执行呢?

如下所示:

将当前的bean对象通过scope属性设置为多例:

 <bean id="user" class="projo.User" init-method="initMethod" destroy-method="destroyMethod" scope="prototype">

我们再次运行测试类,会发现什么都没输出

在这里插入图片描述

那么也就是说,我们通过将bean的作用域设置为多例,每次获取到的对象都是新的,那么也就没有必要在获取IOC容器的时候将其创建好

将获取bean对象的代码添加,我发现和上述不同的时,对象创建有关的三个方法都被调用,那么足以说明,当bean对象的作用域为多例的情况下,对象的创建是在获取bean对象时完成的

在这里插入图片描述

由此还有一点不知道大家是否注意到,此时我们即使调用了close方法,但是销毁的方法依然没有被调用,原因是:当我们将bean对象的作用域设置为多例的时候,其销毁的方法就不由IOC容器控制了

bean的后置处理器:

bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有的bean都会执行

创建新的类,使其实现BeanPostProcessor接口:

package process;import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPostProcessor implements BeanPostProcessor {
}

仅仅实现该接口,并没有实现其中的方法,我们会发现,也是没有任何的报错的,Ctrl+b跟进源码, 如下所示,我们发现该接口中的方法原来是使用default关键字修饰的,

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.beans.factory.config;import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}

那么这两个方法到底有什么作用呢?

看方法名postProcessBeforeInitialization[初始化前的后置处理],postProcessAfterInitialization[初始化后的后置处理],下面我们对其进行重写,输出一些信息,如下所示:

package process;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("MyBeanPostProcessor--- >后置处理器postProcessBeforeInitialization");//此方法在bean的生命周期初始化之前执行return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("MyBeanPostProcessor--- >后置处理器postProcessAfterInitialization");//此方法在bean的生命周期初始化之后执行return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}

你以为这就可以对bean对象进行处理了吗?当然不是,我们还需要将其配置到IOC容器中,如下所示:

 <bean id="myBeanPostProcessor" class="process.MyBeanPostProcessor">

此时进行测试,输出如下:

在这里插入图片描述

我们发现上述在MyBeanPostProcessor类中所添加的两条语句都被输出了,那么后置处理器到底是对那个bean起作用呢?答案是:对当前IOC容器中的每个bean起作用,它会对每个bean在初始化前后都添加额外的操作

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

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

相关文章

Spring Quartz项目实现Job的动态控制

一、简单介绍 Quartz可以对job进行简单控制&#xff0c;但不支持分布式&#xff0c;也没有管理界面和任务分片&#xff0c;但使用起来比较简易。 二、创建简单Demo 我们开始简单使用一下&#xff0c;首先创建Demo&#xff0c;在pom文件中加入以下依赖。 <parent><g…

golang项目实战2023/03/21

初始化项目首先建立一个文件夹在文件夹下面建一个main.go文件执行初始化命令行go mod init page // page 为自己的项目名称 go mod tidy 安装框架 go get gorm.io/gorm // gorm go get gorm.io/driver/mysql // 这里是用的sql数据库 go get -u github.com/gin-gonic/gin // 这…

Numpy 广播域

NumPy广播(Broadcast)&#xff0c;广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式&#xff0c; 对数组的算术运算通常在相应的元素上进行。不同形状指的是&#xff0c;大小不同当然不是指的维度&#xff0c;但是要求数组各维度的长度相同例如&#xff1a;…

ICG-MAL,吲哚菁绿-马来酰亚胺,CAS:2143933-81-5,科研级别试剂

ICG-MAL,吲哚菁绿-马来酰亚胺 中文名称&#xff1a;吲哚菁绿-马来酰亚胺 英文名称&#xff1a;ICG-MAL 性状&#xff1a;粉末或固体 CAS&#xff1a;2143933-81-5 分子式&#xff1a;C51H56N4O6S 分子量&#xff1a;853.09 溶剂&#xff1a;溶于二氯甲烷等常规性有机溶…

【洛谷刷题】蓝桥杯专题突破-深度优先搜索-dfs(7)

目录 写在前面&#xff1a; 题目&#xff1a;P1596 [USACO10OCT]Lake Counting S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述&#xff1a; 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 解题思路&#xff1a; …

【技巧】十大深度学习技巧和经验总结

✅作者简介&#xff1a;在读博士&#xff0c;伪程序媛&#xff0c;人工智能领域学习者&#xff0c;深耕机器学习&#xff0c;交叉学科实践者&#xff0c;周更前沿文章解读&#xff0c;提供科研小工具&#xff0c;分享科研经验&#xff0c;欢迎交流&#xff01;&#x1f4cc;个人…

RocketMQ重复消费问题的原因

文章目录 概览消息发送异常时重复发送消费消息抛出异常消费者提交offset失败服务端持久化offset失败主从同步offset失败重平衡清理长时间消费的消息总结概览 消息发送异常时重复发送 首先,我们来瞅瞅RocketMQ发送消息和消费消息的基本原理。 如图,简单说一下上图中的概念: …

责任链设计模式的一次实践

业务需求 框架&#xff1a;SSH 需要对全部接口的响应体 ResponseBody 做 XSS 拦截 解决方案 在全局拦截器中检测 Response Body 是否有非法字符&#xff0c;如果有&#xff0c;就抛出异常。 实际上&#xff0c;在 struts2 的拦截器上&#xff0c;我发现 即使修改了 action…

yum安装docker以及安装指定版本docker

Docker是Docker.Inc公司开源的一个基于轻量级虚拟化技术的容器引擎项目,整个项目基于Go语言开发&#xff0c;并遵从Apache 2.0协议。通过分层镜像标准化和内核虚拟化技术&#xff0c;Docker使得应用开发者和运维工程师可以以统一的方式跨平台发布应用&#xff0c;并且以几乎没有…

在Java中,使用HttpUtils实现发送HTTP请求

HTTP请求&#xff0c;在日常开发中&#xff0c;还是比较常见的&#xff0c;今天给大家分享HttpUtils如何使用。 阅读本文&#xff0c;你将收获&#xff1a; 简单总结HTTP请求常用配置&#xff1b;JavaLib中HttpUtils如何使用&#xff1b;如何封装HTTP请求工具类。 第一部分&a…

【Unity入门】3D物体

【Unity入门】3D物体 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;物体移动旋转缩放 &#xff08;1&#xff09;物体移动 在上一篇文章【Unity入门】场景视图操作我们学会了在场景中创建3…

开源供应链管理系统 S2B2B2C系统方案及源码输出

连锁供应链的管理&#xff0c;包括供应链的仓库管理、业务员管理、门店订货管理、门店管理、门店前端拓客管理&#xff0c;相关的功能结构图如下&#xff1a; 整个方案含PC、小程序端&#xff0c;源码&#xff01; 功能列表&#xff1a; 仓库管理&#xff1a;包括仓库布局、库存…

Fabric系列 - TLS身份验证

排序节点&#xff08;Orderer&#xff09;要启用TLS身份验证 对等节点&#xff08;Peer&#xff09;要启用TLS的身份验证 Gossip 消息传递 gossip 层使用 TLS 绑定来验证连接另一端的对等方的身份。 通过 Peer 节点 TLS 层来处理点对点消息的安全性&#xff0c;不需要使用签名…

OpenAI创始人:GPT-4的研究起源和构建心法

OneFlow编译 翻译&#xff5c;杨婷、贾川、徐佳渝 三十年前&#xff0c;互联网&#xff08;Web 1.0&#xff09;时代开启。人们只能在笨重的电脑上用鼠标点击由HTML编写的网页文本&#xff0c;随后开始支持插入图片&#xff0c;可以上传视频&#xff0c;于是有了网络新闻、搜索…

一次小破站JS代码审计出XSS漏洞思路学习

今天看了小破站一个大佬的分析&#xff0c;感觉思路很有意思&#xff0c;感兴趣的xdm可以到大佬视频下提供的链接进行测试&#xff08;传送门&#xff09;这类社交平台的XSS漏洞利用起来其实危害是特别大的&#xff0c;利用XSS能在社交平台上呈现蠕虫式的扩散&#xff0c;大部分…

【人人都能读标准】10. 作用域链与闭包

本文为《人人都能读标准》—— ECMAScript篇的第10篇。我在这个仓库中系统地介绍了标准的阅读规则以及使用方式&#xff0c;并深入剖析了标准对JavaScript核心原理的描述。 在8.执行环境我们说过&#xff0c;由ECMAScript代码创建的执行上下文会有一个词法环境的组件&#xff0…

【Effective C++详细总结】第四章 设计与声明

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;C/C知识点 &#x1f4e3;专栏定位&#xff1a;整理一下 C 相关的知识点&#xff0c;供大家学习参考~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;…

Flink-转换算子

基本转换算子 map(映射) filter&#xff08;过滤&#xff09; flatMap&#xff08;扁平映射&#xff09; 聚合算子 keyBy&#xff08;按键分区&#xff09; 简单聚合 reduce&#xff08;归约聚合&#xff09; UDF介绍 函数类 富函数类 数据源读入数据之后&#xff0c;我们就可…

Neodynamic EPLPrinter SDK 2.0 for .NET Crack

Neodynamic EPLPrinter Emulator SDK for .NET Standard V2.0 添加对 FK&#xff08;删除表单&#xff09;、FR&#xff08;检索表单&#xff09;和 FS&#xff08;存储表单&#xff09;表单相关命令的支持。 21月 2023&#xff0c; 10 - 34&#xff1a;<>新版本 特征…

如何在24小时内让你的网站跻身谷歌前列?

在当今互联网时代&#xff0c;拥有一个排名靠前的网站对于企业来说非常重要&#xff0c;因为这意味着更多的流量和更高的曝光率。 而谷歌&#xff08;Google&#xff09;是全球最受欢迎的搜索引擎之一&#xff0c;因此在谷歌的搜索结果中排名靠前非常重要。 那么如何在24小时…