论坛首页 Java企业应用论坛

【第三章】 DI 之 3.4 Bean的作用域 ——跟我学spring3

浏览 1584 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (16) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-02-21   最后修改:2012-02-21

3.4  Bean的作用域

       什么是作用域呢?即“scope”,在面向对象程序设计中一般指对象或变量之间的可见范围。而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围。

Spring提供“singleton”和“prototype”两种基本作用域,另外提供“request”、“session”、“global session”三种web作用域;Spring还允许用户定制自己的作用域。

3.4.1  基本的作用域

       一、singleton指“singleton”作用域的Bean只会在每个Spring IoC容器中存在一个实例,而且其完整生命周期完全由Spring容器管理。对于所有获取该Bean的操作Spring容器将只返回同一个Bean。

 

GoF单例设计模式指“保证一个类仅有一个实例,并提供一个访问它的全局访问点”,介绍了两种实现:通过在类上定义静态属性保持该实例和通过注册表方式。

       

1)通过在类上定义静态属性保持该实例:一般指一个Java虚拟机 ClassLoader装载的类只有一个实例,一般通过类静态属性保持该实例,这样就造成需要单例的类都需要按照单例设计模式进行编码;Spring没采用这种方式,因为该方式属于侵入式设计;代码样例如下:

 

java代码:
  1. package cn.javass.spring.chapter3.bean;  
  2. public class Singleton {  
  3.     //1.私有化构造器  
  4.     private Singleton() {}  
  5.     //2.单例缓存者,惰性初始化,第一次使用时初始化  
  6.     private static class InstanceHolder {  
  7.         private static final Singleton INSTANCE = new Singleton();  
  8.     }  
  9.     //3.提供全局访问点  
  10.     public static Singleton getInstance() {  
  11.         return InstanceHolder.INSTANCE;  
  12.     }  
  13.     //4.提供一个计数器来验证一个ClassLoader一个实例  
  14.     private int counter=0;  
  15. }  

 

 

以上定义个了个单例类,首先要私有化类构造器;其次使用InstanceHolder静态内部类持有单例对象,这样可以得到惰性初始化好处;最后提供全局访问点getInstance,使得需要该单例实例的对象能获取到;我们在此还提供了一个counter计数器来验证一个ClassLoader一个实例。具体一个ClassLoader有一个单例实例测试请参考代码“cn.javass.spring.chapter3. SingletonTest”中的“testSingleton”测试方法,里边详细演示了一个ClassLoader有一个单例实例。

 

 

1)  通过注册表方式: 首先将需要单例的实例通过唯一键注册到注册表,然后通过键来获取单例,让我们直接看实现吧,注意本注册表实现了Spring接口“SingletonBeanRegistry”,该接口定义了操作共享的单例对象,Spring容器实现将实现此接口;所以共享单例对象通过“registerSingleton”方法注册,通过“getSingleton”方法获取,消除了编程方式单例,注意在实现中不考虑并发:

 

 

java代码:
  1. package cn.javass.spring.chapter3;  
  2. import java.util.HashMap;  
  3. import java.util.Map;  
  4. import org.springframework.beans.factory.config.SingletonBeanRegistry;  
  5. public class SingletonBeanRegister implements SingletonBeanRegistry {  
  6.     //单例Bean缓存池,此处不考虑并发  
  7.     private final Map<String, Object> BEANS = new HashMap<String, Object>();  
  8.     public boolean containsSingleton(String beanName) {  
  9.         return BEANS.containsKey(beanName);  
  10.     }  
  11.     public Object getSingleton(String beanName) {  
  12.         return BEANS.get(beanName);  
  13.     }  
  14.     @Override  
  15.     public int getSingletonCount() {  
  16.         return BEANS.size();  
  17.     }  
  18.     @Override  
  19.     public String[] getSingletonNames() {  
  20.         return BEANS.keySet().toArray(new String[0]);  
  21.     }  
  22.     @Override  
  23.     public void registerSingleton(String beanName, Object bean) {  
  24.         if(BEANS.containsKey(beanName)) {  
  25.             throw new RuntimeException("[" + beanName + "] 已存在");  
  26.         }  
  27.         BEANS.put(beanName, bean);  
  28. }  
  29. }  
  30.    

 

Spring是注册表单例设计模式的实现,消除了编程式单例,而且对代码是非入侵式。

接下来让我们看看在Spring中如何配置单例Bean吧,在Spring容器中如果没指定作用域默认就是“singleton”,配置方式通过scope属性配置,具体配置如下:

 

java代码:
  1. <bean  class="cn.javass.spring.chapter3.bean.Printer" scope="singleton"/>  

 

       Spring管理单例对象在Spring容器中存储如图3-5所示,Spring不仅会缓存单例对象,Bean定义也是会缓存的,对于惰性初始化的对象是在首次使用时根据Bean定义创建并存放于单例缓存池。

 

图3-5 单例处理

 

二、prototype即原型,指每次向Spring容器请求获取Bean都返回一个全新的Bean,相对于“singleton”来说就是不缓存Bean,每次都是一个根据Bean定义创建的全新Bean。

 

GoF原型设计模式,指用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

 

Spring中的原型和GoF中介绍的原型含义是不一样的:

         GoF通过用原型实例指定创建对象的种类,而Spring容器用Bean定义指定创建对象的种类;

         GoF通过拷贝这些原型创建新的对象,而Spring容器根据Bean定义创建新对象。

其相同地方都是根据某些东西创建新东西,而且GoF原型必须显示实现克隆操作,属于侵入式,而Spring容器只需配置即可,属于非侵入式。

 

接下来让我们看看Spring如何实现原型呢?

 

1)首先让我们来定义Bean“原型”:Bean定义,所有对象将根据Bean定义创建;在此我们只是简单示例一下,不会涉及依赖注入等复杂实现:BeanDefinition类定义属性“class”表示原型类,“id”表示唯一标识,“scope”表示作用域,具体如下:

 

java代码:
  1. package cn.javass.spring.chapter3;  
  2. public class BeanDefinition {  
  3.     //单例  
  4.     public static final int SCOPE_SINGLETON = 0;  
  5. font-size: 12px; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-left-width:

论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics