SpringBean作用域

在配置文件中,除了可以定义Bean的属性值和相互之间的依赖关系,还可以声明Bean的作用域。例如,如果每次获取Bean时,都需要一个Bean实例,那么应该将Bean的scope属性定义为prototype,如果Spring需要每次都返回一个相同的Bean实例,则应将Bean的scope属性定义为singleton。

作用域的种类

Spring容器在初始化一个Bean实例时,同时会指定该实例的作用域。Spring5支持以下6种作用域。

1)singleton

默认值,单例模式,表示在Spring容器中只有一个Bean实例,Bean以单例的方式存在。

2)prototype

原型模式,表示每次通过Spring容器获取Bean时,容器都会创建一个Bean实例。

3)request

每次HTTP请求,容器都会创建一个Bean实例。该作用域只在当前HTTPRequest内有效。

4)session

同一个HTTPSession共享一个Bean实例,不同的Session使用不同的Bean实例。该作用域仅在当前HTTPSession内有效。

5)application

同一个Web应用共享一个Bean实例,该作用域在当前ServletContext内有效。

类似于singleton,不同的是,singleton表示每个IoC容器中仅有一个Bean实例,而同一个Web应用中可能会有多个IoC容器,但一个Web应用只会有一个ServletContext,也可以说application才是Web应用中货真价实的单例模式。

6)websocket

websocket的作用域是WebSocket,即在整个WebSocket中有效。

注意:Spring5版本之前还支持globalSession,该值表示在一个全局的HTTPSession中,容器会返回该Bean的同一个实例。一般用于Portlet应用环境。Spring5.2.0版本中已经将该值移除了。

request、session、application、websocket和globalSession作用域只能在Web环境下使用,如果使用ClassPathXmlApplicationContext加载这些作用域中的任意一个的Bean,就会抛出以下异常。

java.lang.IllegalStateException: No Scope registered for scope name 'xxx'1复制代码类型:[java]

下面我们详细讲解常用的两个作用域:singleton和prototype。

singleton

singleton是Spring容器默认的作用域。当Bean的作用域为singleton时,Spring容器中只会存在一个共享的Bean实例。该Bean实例将存储在高速缓存中,并且所有对Bean的请求,只要id与该Bean定义相匹配,都会返回该缓存对象。

通常情况下,这种单例模式对于无会话状态的Bean(如DAO层、Service层)来说,是最理想的选择。

在Spring配置文件中,可以使用<bean>元素的scope属性,将Bean的作用域定义成singleton,其配置方式如下所示:

<bean id="..." class="..." scope="singleton"/>1复制代码类型:[java]

例1

下面使用EclipseIDE演示如何将Bean的作用域指定为singleton,步骤如下:

1、创建SpringDemo项目,并在src目录下创建net.biancheng包。

2、添加相应的jar包,可以参考《第一个Spring程序》一节。

3、在net.biancheng包下创建HelloWorld和MainApp类。

4、在src目录下创建Spring配置文件Beans.xml。

运行SpringDemo项目。

HelloWorld类代码如下。

package net.biancheng;public class HelloWorld { private String message; public void setMessage(String message) {  this.message = message;
 } public void getMessage() {
  System.out.println("message : " + message);
 }
}12345678910复制代码类型:[java]

MainApp类如下。

package net.biancheng;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class MainApp { public static void main(String[] args) {
  ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
  HelloWorld objA = (HelloWorld) context.getBean("helloWorld");
  objA.setMessage("对象A");
  objA.getMessage();
  HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
  objB.getMessage();
 }
}12345678910111213复制代码类型:[java]

Beans.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-3.0.xsd">
 <bean id="helloWorld" class="net.biancheng.HelloWorld" scope="singleton"/>

</beans>12345678复制代码类型:[java]

运行结果如下。

message : 对象A
message : 对象A12复制代码类型:[java]

从运行结果可以看出,两次输出内容相同,这说明Spring容器只创建了一个HelloWorld类的实例。由于Spring容器默认作用域是singleton,所以如果省略scope属性,其输出结果也会是一个实例。

prototype

对于prototype作用域的Bean,Spring容器会在每次请求该Bean时都创建一个新的Bean实例。prototype作用域适用于需要保持会话状态的Bean(如Struts2的Action类)。

在Spring配置文件中,可以使用<bean>元素的scope属性,将Bean的作用域定义成prototype,其配置方式如下所示:

<bean id="..." class="..." scope="prototype"/>1复制代码类型:[java]

例2

在例1的基础上,修改配置文件Beans.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-3.0.xsd">
 <bean id="helloWorld" class="net.biancheng.HelloWorld" scope="prototype"/>

</beans>12345678复制代码类型:[java]

运行结果如下。

message : 对象A
message : null12复制代码类型:[java]

从运行结果可以看出,两次输出的内容并不相同,这说明在prototype作用域下,Spring容器创建了两个不同的HelloWorld实例。

(0)

相关推荐

  • 大佬把Spring框架总结的「无比详细」,看完还说不懂别学了

    大佬把Spring框架总结的「无比详细」,看完还说不懂别学了

  • Spring学习02(DI依赖注入)

    5.依赖注入(Dependency Injection,DI) 5.1 概念 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 . 注入 : 指Bean对象所依赖的资源 , 由容器 ...

  • C++的标识符的作用域与可见性

    下面是关于C++的标识符的作用域与可见性学习记录,仅供参考 标识符的作用域与可见性 作用域是一个标识符在程序正文中有效的区域. 作用域分类 ①函数原型作用域 ②局部作用域(快作用域) ③类作用域 ④文 ...

  • [js] 第106天 说说你对作用域链的理解

    今日试题: 说说你对作用域链的理解 此开源项目四大宗旨:勤思考,多动手,善总结,能坚持 <论语>,曾子曰:"吾日三省吾身"(我每天多次反省自己). 前端面试每日3+1, ...

  • 终于弄明白了 Singleton,Transient,Scoped 的作用域是如何实现的

    一:背景 1. 讲故事 前几天有位朋友让我有时间分析一下 aspnetcore 中为什么向 ServiceCollection 中注入的 Class 可以做到 Singleton,Transient, ...

  • 什么是JavaScript的作用域

    作用域的概念 现代编程语言的最基本功能之一就是能够存储变量当中的值,以便于之后的使用于修改.也正是这个功能将状态带给了程序. 在JavaScript中,作用域就是一套设计良好的规则来存储变量. 简述编 ...

  • Python 变量作用域 LEGB (下)

    上篇:Python 变量作用域 LEGB (上)-- Local,Global,Builtin https://www.cnblogs.com/yvivid/p/python_LEGB_1.html ...

  • SpringBean生命周期

    在传统的Java应用中,Bean的生命周期很简单,使用关键字new实例化Bean,当不需要该Bean时,由Java自动进行垃圾回收. Spring中Bean的生命周期较复杂,可以表示为:Bean的定义 ...

  • 说说Python中变量的作用域?

    公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开始, ...

  • 深入理解JavaScript作用域和作用域链

    目录 前言 作用域(Scope) 1.什么是作用域 2.全局作用域和函数作用域 3.块级作用域 作用域链 1.什么是自由变量 2.什么是作用域链 3.关于自由变量的取值 作用域与执行上下文 解释阶段: ...

  • C语言变量作用域以及栈,堆困惑!!!!

    https://m.toutiao.com/is/Jn8m7wr/ 这几天遇到一段很困惑的代码.用函数内部变量地址做返回值时候,没法正确返回变量a地址,返回的是OX0如下: 我在函数内部再加一个指针q ...