3.1 Bean对象的单例和多例概述

在Spring容器中管理的Bean对象的作用域,可以通过scope属性或用相关注解指定其作用域。
最常用是singleton(单例)或prototype(多例)。其含义如下:

  • singleton:单实例,是默认值。这个作用域标识的对象具备全局唯一性。
    当把一个 bean 定义设置scope为singleton作用域时,那么Spring IOC容器只会创建该bean定义的唯一实例。也就是说,整个Spring IOC容器中只会创建当前类的唯一一个对象。
    这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的、唯一的这个对象实例。
    singleton负责对象的创建、初始化、销毁。

  • prototype:多实例。这个作用域标识的对象每次获取都会创建新的对象。
    当把一个 bean 定义设置scope为singleton作用域时,Spring IOC容器会在每一次获取当前Bean时,都会产生一个新的Bean实例(相当于new的操作)
    prototype只负责对象的创建和初始化,不负责销毁。

3.2 为什么用单实例或多实例?

之所以用单实例,在没有线程安全问题的前提下,没必要每个请求都创建一个对象,这样子既浪费CPU又浪费内存;
之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态(例如,可改变的成员变量),此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;
用单例和多例的标准只有一个:当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),使用多实例,否则单实例;

在Spring中配置Bean实例是单例还是多例方法是:
单例:

<bean id="hello" scope="singleton" class="com.tedu.spring.Hello"></bean>

多例:

<bean id="hello" scope="prototype" class="com.tedu.spring.Hello"></bean>

3.3 测试spring的单实例和多实例

1、创建TestIOC2类,测试代码如下:

package com.tedu.spring;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIOC2 {
	public static void main(String[] args) {
		/* 通过spring容器创建创建Hello对象, * 并调用Hello中的sayHi方法 */
		//1.加载spring的核心配置文件
		ClassPathXmlApplicationContext ac = 
				new ClassPathXmlApplicationContext(
					"applicationContext.xml"
				);
		//2.从spring容器中获取bean对象(而不是自己new)
		Hello hello1 = (Hello) ac.getBean("hello");
		Hello hello2 = (Hello) ac.getBean("hello");
		
		//3.测试
		if(hello1 == hello2){
			System.out.println("当前实例为单实例...");
		}else{
			System.out.println("当前实例为多实例...");
		}
	}
}

3、将applicationContext.xml中,Hello类bean标签的scope值设置为singleton:

<bean id="hello" scope="singleton" class="com.tedu.spring.Hello"></bean>

运行TestIOC2,运行结果为:

4、将applicationContext.xml中,Hello类bean标签的scope值修改为prototype

<bean id="hello" scope="prototype" class="com.tedu.spring.Hello"></bean>

再次运行TestIOC2,运行结果为: