(四)Spring Bean 作用域

(四)Spring Bean 作用域

 

1、Bean 的作用域

       当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为 singleton

Spring 框架支持以下五个作用域,分别为 singleton、prototype、request、session 和 global session,5种作用域说明如下所示,

注意,如果你使用 web-aware ApplicationContext 时,其中三个是可用的。   

作用域描述
singleton

在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值

prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
global-session 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境

application

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

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

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

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

java.lang.IllegalStateException: No Scope registered for scope name 'xxx'

 

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

    2.1、singleton

     singleton 是 Spring 容器默认的作用域。当 Bean 的作用域为 singleton 时,Spring 容器中只会存在一个共享的 Bean 实例。该 Bean 实例将存储在高速缓存中,并且所有对 Bean 的请求,只要 id 与该 Bean 定义相匹配,都会返回该缓存对象。
通常情况下,这种单例模式对于无会话状态的 Bean(如 DAO 层、Service 层)来说,是最理想的选择。
在 Spring 配置文件中,可以使用 <bean> 元素的 scope 属性,将 Bean 的作用域定义成 singleton,其配置方式如下所示:

<bean id="..." class="..." scope="singleton"/>

下面举例说明 SpringBean 默认是单例的

HelloWorld 类代码如下:

public class HelloWorld {
    private String message;
    public void setMessage(String message) {
        this.message = message;
    }
    public void getMessage() {
        System.out.println("message : " + message);
    }
}

MainApp 类如下:

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();
    }
}

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="com.dw.study.HelloWorld"/>
      
</beans>

运行结果如下:

message : 对象A
message : 对象A

从运行结果可以看出,两次输出内容相同,这说明 Spring 容器只创建了一个 HelloWorld 类的实例。 Spring 容器默认作用域是 singleton

 

  2.2、prototype

对于 prototype 作用域的 Bean,Spring 容器会在每次请求该 Bean 时都创建一个新的 Bean 实例。

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

<bean id="..." class="..." scope="prototype"/>

修改上面例子的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="com.dw.study.HelloWorld" scope="prototype"/>
      
</beans>

运行结果如下:

message : 对象A
message : null

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

 

posted @ 2021-07-27 22:40  邓维-java  阅读(358)  评论(0)    收藏  举报