详解Spring中Bean的作用域与生命周期
摘要:在利用Spring进行IOC配置时,关于bean的配置和使用一直都是比较重要的一部分,同时如何合理的使用和创建bean对象,也是小伙伴们在学习和使用Spring时需要注意的部分,所以这一篇文章我就来和大家讲一下有关Spring中bean的作用域和其生命周期。
本文分享自华为云社区《详解Spring中Bean的作用域与生命周期》,原文作者:灰小猿。
在利用Spring进行IOC配置时,关于bean的配置和使用一直都是比较重要的一部分,同时如何合理的使用和创建bean对象,也是小伙伴们在学习和使用Spring时需要注意的部分,所以这一篇文章我就来和大家讲一下有关Spring中bean的作用域和其生命周期。
一、Bean的作用域
首先我们来讲一下有关于bean的作用域,
一般情况下,我们书写在IOC容器中的配置信息,会在我们的IOC容器运行时被创建,这就导致我们通过IOC容器获取到bean对象的时候,往往都是获取到了单实例的Bean对象,
这样就意味着无论我们使用多少个getBean()方法,获取到的同一个JavaBean都是同一个对象,这就是单实例Bean,整个项目都会共享这一个bean对象。
在Spring中,可以在<bean>元素的scope属性里设置bean的作用域,以决定这个bean是单实例的还是多实例的。Scope属性有四个参数,具体的使用可以看下图:
1、单实例Bean声明
默认情况下,Spring只为每个在IOC容器里声明的bean创建唯一一个实例,整个IOC容器范围内都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例。该作用域被称为singleton,它是所有bean的默认作用域。也就是单实例。
为了验证这一说法,我们在IOC中创建一个单实例的bean,并且获取该bean对象进行对比:
<!-- singleton单实例bean
1、在容器创建时被创建
2、只有一个实例
-->
<bean id="book02" class="com.spring.beans.Book" scope="singleton"></bean>
测试获取到的单实例bean是否是同一个:
@Test
public void test09() {
// 单实例创建时创建的两个bean相等
Book book03 = (Book)iocContext3.getBean("book02");
Book book04 = (Book)iocContext3.getBean("book02");
System.out.println(book03==book04);
}
得到的结果是true;
2、多实例Bean声明
而既然存在单实例,那么就一定存在多实例。我们可以为bean对象的scope属性设置prototype参数,以表示该实例是多实例的,同时获取IOC容器中的多实例bean,再将获取到的多实例bean进行对比,
<!-- prototype多实例bean
1、在容器创建时不会被创建,
2、只有在被调用的时候才会被创建
3、可以存在多个实例
-->
<bean id="book01" class="com.spring.beans.Book" scope="prototype"></bean>
测试获取到的多实例bean是否是同一个:
@Test
public void test09() {
// 多实例创建时,创建的两个bean对象不相等
Book book01 = (Book)iocContext3.getBean("book01");
Book book02 = (Book)iocContext3.getBean("book01");
System.out.println(book01==book02);
}
得到的结果是false
这就说明了,通过多实例创建的bean对象是各不相同的。
在这里需要注意:
同时关于单实例和多实例bean的创建也有不同,当bean的作用域为单例时,Spring会在IOC容器对象创建时就创建bean的对象实例。而当bean的作用域为prototype时,IOC容器在获取bean的实例时创建bean的实例对象。
二、Bean的生命周期
1、bean的初始和销毁
其实我们在IOC中创建的每一个bean对象都是有其特定的生命周期的,在Spring的IOC容器中可以管理bean的生命周期,Spring允许在bean生命周期内特定的时间点执行指定的任务。如在bean初始化时执行的方法和bean被销毁时执行的方法。
Spring IOC容器对bean的生命周期进行管理的过程可以分为六步:
- 通过构造器或工厂方法创建bean实例
- 为bean的属性设置值和对其他bean的引用
- 调用bean的初始化方法
- bean可以正常使用
- 当容器关闭时,调用bean的销毁方法
那么关于bean的初始和销毁时执行的方法又该如何声明呢?
首先我们应该在bean类内部添加初始和销毁时执行的方法。如下面这个javabean:
package com.spring.beans; public class Book {
private String bookName;
private String author;
/**
* 初始化方法
* */
public void myInit() {
System.out.println("book bean被创建");
} /**
* 销毁时方法
* */
public void myDestory() {
System.out.println("book bean被销毁");
} public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book [bookName=" + bookName + ", author=" + author + "]";
}
}
这时我们在配置bean时,可以通过init-method和destroy-method 属性为bean指定初始化和销毁方法,
<!-- 设置bean的生命周期
destory-method:结束调用的方法
init-method:起始时调用的方法
-->
<bean id="book01" class="com.spring.beans.Book" destroy-method="myDestory" init-method="myInit"></bean>
这样当我们在通过IOC容器创建和销毁bean对象时就会执行相应的方法,
但是这里还是有一点需要注意:
我们上面说了,单实例的bean和多实例的bean的创建时间是不同的,那么他们的初始方法和销毁方法的执行时间就稍稍有不同。
- 单实例下 bean的生命周期
容器启动——>初始化方法——>(容器关闭)销毁方法
- 多实例下 bean的生命周期
容器启动——>调用bean——>初始化方法——>容器关闭(销毁方法不执行)
2、bean的后置处理器
什么是bean的后置处理器?bean后置处理器允许在调用初始化方法前后对bean进行额外的处理
bean后置处理器对IOC容器里的所有bean实例逐一处理,而非单一实例。
其典型应用是:检查bean属性的正确性或根据特定的标准更改bean的属性。
bean后置处理器使用时需要实现接口:
org.springframework.beans.factory.config.BeanPostProcessor。
在初始化方法被调用前后,Spring将把每个bean实例分别传递给上述接口的以下两个方法:
postProcessBeforeInitialization(Object, String)调用前
postProcessAfterInitialization(Object, String)调用后
如下是一个实现在该接口的后置处理器:
package com.spring.beans; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; /**
* 测试bean的后置处理器
* 在这里要注意一点是为了出现bean和beanName,而不是arg0、arg1,需要绑定相应的源码jar包
* */
public class MyBeanPostProcessor implements BeanPostProcessor{ /**
* postProcessBeforeInitialization
* 初始化方法执行前执行
* Object bean
* String beanName xml容器中定义的bean名称
* */
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("【"+ beanName+"】初始化方法执行前...");
return bean;
} /**
* postProcessAfterInitialization
* 初始化方法执行后执行
* Object bean
* String beanName xml容器中定义的bean名称
* */
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("【"+ beanName+"】初始化方法执行后...");
return bean;
} }
将该后置处理器加入到IOC容器中:
<!-- 测试bean的后置处理器 -->
<bean id="beanPostProcessor" class="com.spring.beans.MyBeanPostProcessor"></bean>
由于现在我们的bean对象是单实例的,所以容器运行时就会直接创建bean对象,同时也会执行该bean的后置处理器方法和初始化方法,在容器被销毁时又会执行销毁方法。我们测试如下:
//*************************bean生命周期*****************
// 由于ApplicationContext是一个顶层接口,里面没有销毁方法close,所以需要使用它的子接口进行接收
ConfigurableApplicationContext iocContext01 = new ClassPathXmlApplicationContext("ioc1.xml"); @Test
public void test01() {
iocContext01.getBean("book01");
iocContext01.close();
}
运行结果:
总结一下后置处理器的执行过程:
- 通过构造器或工厂方法创建bean实例
- 为bean的属性设置值和对其他bean的引用
- 将bean实例传递给bean后置处理器的postProcessBeforeInitialization()方法
- 调用bean的初始化方法
- 将bean实例传递给bean后置处理器的postProcessAfterInitialization()方法
- bean可以使用了
- 当容器关闭时调用bean的销毁方法
所以添加bean后置处理器后bean的生命周期为:
容器启动——后置处理器的before...——>初始化方法——>后置处理器的after...———>(容器关闭)销毁方法
详解Spring中Bean的作用域与生命周期的更多相关文章
- Spring中Bean的作用域、生命周期
Bean的作用域.生命周期 Bean的作用域 Spring 3中为Bean定义了5中作用域,分别为singleton(单例).protot ...
- Spring中bean的作用域与生命周期
在 Spring 中,那些组成应用程序的主体及由 Spring IOC 容器所管理的对象,被称之为 bean.简单地讲,bean 就是由 IOC 容器初始化.装配及管理的对象,除此之外,bean 就与 ...
- Spring中Bean的作用域和生命周期
作用域的种类 Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域.Spring3 为 Bean 定义了五种作用域,具体如下. 1)singleton 单例模式,使用 sing ...
- Spring之Bean的作用域与生命周期
在前面博客中提到容器启动获得BeanDefinition对象中有一个scope 属性.该属性控制着bean对象的作用域.本章节介绍Bean的作用域及生命周期,了解bean是怎么来的又怎么没的. 一.B ...
- 【Spring】详解Spring中Bean的加载
之前写过bean的解析,这篇来讲讲bean的加载,加载要比bean的解析复杂些,该文之前在小编原文中有发表过,要看原文的可以直接点击原文查看,从之前的例子开始,Spring中加载一个bean的方式: ...
- 阶段3 2.Spring_03.Spring的 IOC 和 DI_8 spring中bean的细节之生命周期
区分单例还是多例对象 单例的几个状态 初始化方法和销毁方法 设置成我们定义的方法 测试 有创建和初始化.但是没有销毁,.对象一直没有销毁的方法 main方法是一切应用程序的入门.当main方法结束后. ...
- 用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)
用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心.依赖注入(DI)是 ...
- 使用IDEA详解Spring中依赖注入的类型(上)
使用IDEA详解Spring中依赖注入的类型(上) 在Spring中实现IoC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(例如属性值)注入Bean组件 ...
- spring中bean的作用域属性singleton与prototype的区别
1.singleton 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会 ...
随机推荐
- [ Java面试题 ]Java 开发岗面试知识点解析
如背景中介绍,作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向. 在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几个部分: Java 基础知识点 Jav ...
- Jmeter——元件扩展,使其功能更全面
工具扩展 在之前的博文中,有介绍自定义函数.Java请求扩展,博文如下: Jmeter二次开发--基于Java请求 Jmeter二次开发--自定义函数 上述内容,是按自己的需要来进行针对性扩展,从而实 ...
- MLPerf Inference 0.7应用
MLPerf Inference 0.7应用 三个趋势继续推动着人工智能推理市场的训练和推理:不断增长的数据集,日益复杂和多样化的网络,以及实时人工智能服务. MLPerf 推断 0 . 7 是行业标 ...
- flume实时采集mysql数据到kafka中并输出
环境说明 centos7(运行于vbox虚拟机) flume1.9.0(flume-ng-sql-source插件版本1.5.3) jdk1.8 kafka(版本忘了后续更新) zookeeper(版 ...
- 重新整理 .net core 实践篇—————静态中间件[二十一]
前言 简单整理一下静态中间件. 正文 我们使用静态文件调用: app.UseStaticFiles(); 那么这个默认会将我们根目录下的wwwroot作为静态目录. 这个就比较值得注意的,可能刚开始学 ...
- SpringBoot和Spring到底有没有本质的不同?
现在的Spring相关开发都是基于SpringBoot的.最后在打包时可以把所有依赖的jar包都打进去,构成一个独立的可执行的jar包.如下图: 使用java -jar命令就可以运行这个独立的jar包 ...
- Django(68)drf分页器的使用
前言 当后台返回的数据过多时,我们就要配置分页器,比如一页最多只能展示10条等等,drf中默认配置了3个分页面 PageNumberPagination:基础分页器,性能略差 LimitOffsetP ...
- 【模板】关于vector的lower_bound和upper_bound以及vector基本用法 STL
关于lower_bound和upper_bound 共同点 函数组成: 一个数组元素的地址(或者数组名来表示这个数组的首地址,用来表示这个数组的开头比较的元素的地址,不一定要是首地址,只是用于比较的& ...
- ES7扩展
前一段时间小编一直在更新javascript es6版本的部分新语法和新特性,鉴于现在js一直在更新,接下来小编将和大家一起进步,一块探究js的新特性.今天小编就和大家一起来看看es7更新的语法和新特 ...
- Web端在线实时聊天,基于WebSocket(前后端分离)
这是一个简易的Demo,已经实现了基础的功能 之前一直想实现一个实时聊天的系统,一直没有去实践他.有一天吃饭的时候扫码点菜,几个人点菜能够实时更新,当时就在想,这应该是同一种技术. 刚好前段时间项目上 ...