首页 > 代码库 > Spring Bean的作用域

Spring Bean的作用域

1. 常用的两种作用域

  ?  scope="singleton"

  ?  scope="prototype"

  首先,scope="singleton"是Spring的IoC容器创建Bean的默认作用域,它表示每个Bean只会创建一次,并将该Bean的状态进行保存,然后再次从IoC容器中拿同一个Bean时直接取用即可,不用再次创建。

  然后, scope="prototype"表示,每次从IoC容器中拿同一个Bean时都会全新地创建一个Bean,IoC容器不会保存Bean的状态。


2.  使用方法

  两种作用域的使用需遵照一定的原则,即:

  ?  有状态的Bean采用scope="prototype"作用域,为了防止多线程下的线程安全问题。

  ?  无状态的Bean采用默认的scope="singleton"的作用域,因为首先它不存在线程安全问题,其次,这样就可以共享实例,提高程序性能。

 具体一下:

  ?  Struts2中的Action因为会有User、BizEntity这样的实例对象,是有状态信息的,在多线程环境下是不安全的。所以,在Spring中,Struts2的Action中,scope 要配成prototype作用域。

  ?  而Service层、Dao层用默认singleton就行,虽然Service类也有dao这样的属性,但dao这些类都是没有状态信息的,也就是相当于不变(immutable)类,所以不影响。

  下面解释,“线程安全”与“有状态、无状态”的概念。


3.  线程安全

  当对一个复杂对象进行某种操作时,从操作开始到操作结束,被操作的对象往往会经历若干非法的中间状态。调用一个函数(假设该函数是正确的)操作某对象常常会使该对象暂时陷入不可用的状态(通常称为不稳定状态),等到操作完全结束,该对象才会重新回到完全可用的状态。如果其他线程企图访问一个处于不可用状态的对象,该对象将不能正确响应从而产生无法预料的结果。

  由以上可知,线程安全问题,是由于多个线程,同时操作某一个对象时可能引发的问题。也就是说,线程安全问题基本上都是由全局变量及静态变量引起的

  若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

  由此可知:

  ?  常量始终是线程安全的,因为只存在读操作。

  ?  每次调用方法前都新建一个实例是线程安全的,因为不会访问共享的资源。

  ?  局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量和方法内变量。


4.  有状态&无状态

       首先,我们经常用的Http协议是无状态的,浏览器请求完服务器就会立刻断开,不会一直连着服务器。服务器不会保存客户端的状态信息,所以为了保持Http连接状态才出现了Cookie和Session。而,有状态的协议中,比如UDP协议,从我们以前经常玩的CS游戏就可以看出,客户端与服务器是一直连着的,否则,如果连一下服务器就断开,等到再次连接上服务器,早就玩死了。

       个人感觉,一个对象的状态信息主要通过它的属性来体现。

  ?  有状态就是有数据存储功能,可以保存数据,可以通过读写它的属性,来区分同一个类的两个不同的对象。它是非线程安全的。在不同方法调用间不保留任何状态。

  ?  无状态就是一次操作,不能保存数据,是不变类,是线程安全的。

  ?  总之,如果一个类的多个对象,可以区分开,那么就说是有状态的;反之,如果一个类的多个对象,是无法区分开的,那么就说是无状态的。

  一个Bean没有成员变量,或者那个Bean的成员变量也是无状态的Bean,那么这个Bean就是无状态的。通常这样的对象都是一些“操作”类,里面都是一些操作方法,例如,Service层、Dao层的类。反之就是有状态的Bean。


5.  总结

  scope="singleton"是Sping创建Bean的默认作用域,同一个id容器只存在一个共享的Bean实例。这样可以共享实例,提高性能。它适用于“无状态Bean”。而为了解决“有状态Bean”在多线程环境下的线程安全问题,出现的scope="prototype",它不共享实例,每次都会创建一个新的Bean。一般Service层、Dao层类都是无状态的,采用默认作用域即可,而Action一般是有状态的,所以需要设置scope="prototype"属性。

Spring Bean的作用域