当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域,在这里主要说的就是大名鼎鼎的singleton–单例模式和prototype–原型模式,这两个Bean的作用域也是在Spring中比较常见的。其中关于单例模式的概念为我的博客中有写到,可以出门右转去找找,这里在不赘述。
一、singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例;注意这里的Spring singleton模式是默认缺省的饿汉模式,启容器时(即实例化容器时),为所有spring配置文件中定义的bean都生成一个实例。
核心代码如下:

class Bean {  
      private static final Bean theBean;  
      private Bean() {}    
      public static Bean getBean() {  
          return theBean;  
      }  
 }

可是这样做会导致系统的开销比较大,为了不占用过大的资源或者是减少开销,一般我会在spring中添加缺省文件:

<beans default-lazy-init="true">

将系统默认的饿汉模式转换成懒汉模式,也就是在第一次请求的时候我们才生成一个实例,在之后的使用中继续调用即可
核心代码如下:

class Bean {  
      private static final Bean theBean;  
      private Bean() {}    
      public static Bean getBean() {  
          if (theBean == null) {  
              theBean = new Bean();  
          }  
          return theBean;  
      }  
 }

二、prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。
对于singleton作用域的 Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成 prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅 使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。
测试代码:

<!-- 默认的作用域:singleton -->
<bean id="p1" class="com.cxg.User" /> 
<!-- 指定的作用域:prototype -->
<bean id="p2" class="com.cxg.User" scope="prototype" />
public class BeanTest {
  public static void main(String args[]) {
    //加载类路径下的beans.xml文件以初始化Spring容器
    ApplicationContext context = new ClassPathXmlApplicationContext();
    //分两次分别取同一个Bean,比较二者是否是同一个对象
    System.out.println(context.getBean("p1") == context.getBean("p1"));
    System.out.println(context.getBean("p2") == context.getBean("p2"));
  }
}

执行结果:

true
false

从结果可以看出,正如上文所述:对于singleton作用域的Bean,每次请求该id的Bean,都将返回同一个实例,而prototype作用域的Bean, 每次请求都将产生全新的实例。
注意:早期指定Bean的作用域也可通过singleton属性指定,该属性只接受两个属性值:true和false,分别代表singleton和prototype的作用域。使用singleton属性则无法指定其他三个作用域。实际上Spring2.X不推荐使用singleton属性指定Bean的作用域,singleton属性是Spring 1.2.X的使用方式。