Spring中Bean的作用域

2014-01-26 14:10

     在配置文件中定义Bean时,用户不但可以配置Bean的属性值以及相互之间的依赖关系,还可以定义Bean的作用域。

     作用域将对Bean的生命周期和创建方式产生影响,在低版本的Spring中,仅有两个作用域:singleton 和 prototype。

     在Sprign2.0中,针对WebApplicationContext新添加了3个新的作用域:request,session,globalSession。

 

一、singleton和prototype

     在低版本的Spring中,由于仅有两个作用域:singleton 和 prototype,所以采用singleton="true|false"的配置方式,Spring为了向后兼容,依旧支持这种配置方式,不过Spring推荐采用新的配置方式:scope="作用域类型"。

    1.singleton作用域

    Spring以容器的方式提供天然的单实例模式功能,任何POJO无需编写特殊的 代码仅通过配置就可以想用单实例模式的大餐。

    因为Spring利用AOP和LocalThread的功能,对非线程安全的变量进行了特殊的处理,使这些非线程安全的类变成了线程安全的类。

<bean id="car1" class="spring.ioc.demo1.Car" scope="singleton"
        p:brand="spring注入-红旗001" 
        p:color="spring注入-紫色" 
        p:maxSpeed="520" />
public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
     //singleton的bean
        Car car1 = ctx.getBean("car1",Car.class);
        System.out.println("单例的car1:"+car1);
        car1.setBrand("改变");
        Car car2 = ctx.getBean("car1",Car.class);
        System.out.println("再次获取单例的car1:"+car2);}

输出:

单例的car1:the car is:spring注入-红旗001, color is:spring注入-紫色, maxspeed is:520
再次获取单例的car1:the car is:改变, color is:spring注入-紫色, maxspeed is:520

     在默认的情况下,Spring的ApplicationContext容器在启动的时候,自动实例化所有的singleton的Bean并缓冲与容器中。

     a.这样首先对Bean提前的实例化操作会及早发现一些潜在的配置问题

     b.Bean将以缓存方式保存,当再次使用时无需再实例化了

     如果用户不希望在容器启动时实例化singleton的Bean,可以通过lazy-init属性进行控制:

<bean id="car1" class="spring.ioc.demo1.Car" scope="singleton"
        p:brand="spring注入-红旗001" 
        p:color="spring注入-紫色" 
        p:maxSpeed="520" 
                lazy-init="true"
/>

     lazy-init="true"的Bean在某些特殊情况下依旧会提前实例化:如果该Bean被其他需要提前实例化的Bean引用到。

 

     2.prototype作用域

     在默认情况下,Spring容器在启动时不实例化prototype的Bean,此外,Spring容器讲prototype的Bean交给调用者后,就不再管理它的生命周期。

<bean id="carPrototype" class="spring.ioc.demo1.Car" scope="prototype"
        p:brand="邦德" 
        p:color="黑色" 
        p:maxSpeed="110" />
public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
     //prototype的bean
        Car carPrototype1 = ctx.getBean("carPrototype",Car.class);
        System.out.println("多例的carPrototype:"+carPrototype1);
        carPrototype1.setBrand("改变");
        Car carPrototype2 = ctx.getBean("carPrototype",Car.class);
        System.out.println("再次获取多例的carPrototype:"+carPrototype2);
}

输出:

多例的carPrototype:the car is:邦德, color is:黑色, maxspeed is:110
再次获取多例的carPrototype:the car is:邦德, color is:黑色, maxspeed is:110

     每次getBean都将得到一个最新状态的Bean.

 

二、Web应用环境相关的Bean的作用域

     1.request作用域

<bean id="car" class="spring.ioc.demo1.Car" scope="request"
        p:brand="邦德" 
        p:color="黑色" 
        p:maxSpeed="110" />

     request作用域的Bean对应一个HTTP请求和生命周期,每次HTTP请求到carBean时,Spring容器创建一个新的carBean,请求处理完毕,销毁这个Bean.

     

     2.session作用域

<bean id="car" class="spring.ioc.demo1.Car" scope="session"
        p:brand="邦德" 
        p:color="黑色" 
        p:maxSpeed="110" />

     carBean的作用域将横跨整个HTTP Session,Session中所有的HTTP请求都将共享一个carBean,当HTTP Session结束后,实例才被销毁。

 

     3.globalSession作用域

<bean id="car" class="spring.ioc.demo1.Car" scope="globalSession"
        p:brand="邦德" 
        p:color="黑色" 
        p:maxSpeed="110" />在

     globalSession作用域类似于session作用域,不过仅在Portlet的web应用中使用。Portlet规范定义了全局Sesson的概念,它被组成portletweb应用的所有子portlet共享。如果不在Portlet的web应用中使用,globalSession自然就等价于session作用域了。