Spring中的Scope
2017-08-11 18:10
225 查看
spring
Framework支持五种作用域(其中有三种只能用在基于web的SpringApplicationContext)。
当一个bean的作用域为singleton, 那么Spring
IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。
换言之,当把一个bean定义设置为singlton作用域时,Spring
IoC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例。
Singleton作用域是Spring中的缺省作用域。即默认值!!!
[html]
view plain
copy
print?
<pre name="code" class="html"><bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>
或者
<bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/>
Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。根据经验,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
请注意,典型情况下,DAO不会被配置成prototype,因为一个典型的DAO不会持有任何会话状态,因此应该使用singleton作用域。
对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype
bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype
bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)
谈及prototype作用域的bean时,在某些方面你可以将Spring容器的角色看作是Java
new操作符的替代者。任何迟于该时间点的生命周期事宜都得交由客户端来处理。在Section
3.5.1, “Lifecycle接口”一节中会进一步讲述Spring
IoC容器中的bean生命周期。
配置实例:
[html]
view plain
copy
print?
<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/>
或者
<beanidbeanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/>
其他作用域,即request、session以及global
session仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架)。
要使用request、session和 global
session作用域的bean(即具有web作用域的bean),在开始设置bean定义之前,还要做少量的初始配置。请注意,假如你只想要“常规的”作用域,也就是singleton和prototype,就不需要这一额外的设置。
在目前的情况下,根据你的特定servlet环境,有多种方法来完成这一初始设置。如果你使用的是Servlet
2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可
org.springframework.web.context.request.RequestContextListener
即:
[html]
view plain
copy
print?
web-app>
...
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
</web-app>
如果你用的是早期版本的web容器(Servlet 2.4以前),那么你要使用一个javax.servlet.Filter的实现。请看下面的web.xml配置片段:
requestContextFilter
org.springframework.web.filter.RequestContextFilter
requestContextFilter
/*
即:
[html]
view plain
copy
print?
<web-app>
..
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
考虑下面bean定义:
针对每次HTTP请求,Spring容器会根据loginAction
bean定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction
bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。
[html]
view plain
copy
print?
<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>
考虑下面bean定义:
针对某个HTTP Session,Spring容器会根据userPreferences
bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,你可以根据需要放心的更改所创建实例的内部状态,而别的HTTP
Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP
Session作用域内的bean也会被废弃掉。
[html]
view plain
copy
print?
<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>
考虑下面bean定义:
global session作用域类似于标准的HTTP
Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet
web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet
Session的生命周期范围内。
请注意,假如你在编写一个标准的基于Servlet的web应用,并且定义了一个或多个具有global
session作用域的bean,系统会使用标准的HTTP Session作用域,并且不会引起任何错误。
[html]
view plain
copy
print?
<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>
能够在HTTP request或者Session(甚至自定义)作用域中定义bean固然很好,但是Spring
IoC容器除了管理对象(bean)的实例化,同时还负责协作者(或者叫依赖)的实例化。如果你打算将一个Http request范围的bean注入到另一个bean中,那么需要注入一个AOP代理来替代被注入的作用域bean。也就是说,你需要注入一个代理对象,该对象具有与被代理对象一样的公共接口,而容器则可以足够智能的从相关作用域中(比如一个HTTP
request)获取到真实的目标对象,并把方法调用委派给实际的对象。
配置文件:spring-relation.xml
[html]
view plain
copy
print?
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
default-autowire="byName" default-lazy-init="true">
<!-- 使用bean的scope属性来配置bean的作用域
singleton:默认值,容器初始化时创建bean实例,在整个容器的生命周期内只创建这一个bean,单例的
prototype:一个bean定义对应多个对象实例。
request:在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。f
global session:在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。 -->
<bean id="car" scope="singleton" class="com.zd.runsharing.maven.springAutowire.Car">
<property name="brand" value="宝马啊汽车品牌"></property>
<property name="price" value="43000000"></property>
</bean>
</beans>
Car类:
[java]
view plain
copy
print?
public class Car {
public Car() {
System.out.println("Car .. constractor....");
}
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
}
[java]
view plain
copy
print?
public class BeanRelationMainTest {
public static void main(String[] args) {
ApplicationContext atx = new ClassPathXmlApplicationContext("spring-relation.xml");
Car car = (Car) atx.getBean("car");
Car car2 = (Car) atx.getBean("car");
System.out.println(car == car2);
}
}
=================================================================================
=================================================================================
=================================================================================
Framework支持五种作用域(其中有三种只能用在基于web的SpringApplicationContext)。
singleton | 在每个Spring IoC容器中一个bean定义对应一个对象实例。 |
prototype | 一个bean定义对应多个对象实例。 |
request | 在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。 |
session | 在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。 |
global session | 在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。 |
1.Singleton作用域
当一个bean的作用域为singleton, 那么SpringIoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。
换言之,当把一个bean定义设置为singlton作用域时,Spring
IoC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例。
Singleton作用域是Spring中的缺省作用域。即默认值!!!
[html]
view plain
copy
print?
<pre name="code" class="html"><bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>
或者
<bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/>
<pre name="code" class="html"><bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 或者 <bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/>
2.Prototype
Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。根据经验,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。请注意,典型情况下,DAO不会被配置成prototype,因为一个典型的DAO不会持有任何会话状态,因此应该使用singleton作用域。
对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype
bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype
bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)
谈及prototype作用域的bean时,在某些方面你可以将Spring容器的角色看作是Java
new操作符的替代者。任何迟于该时间点的生命周期事宜都得交由客户端来处理。在Section
3.5.1, “Lifecycle接口”一节中会进一步讲述Spring
IoC容器中的bean生命周期。
向后兼容性:在XML中指定生命周期作用域 | |
如果你在bean定义文件中引用'spring-beans.dtd' DTD,要显式说明bean的生命周期作用域你必须使用"singleton"属性(记住singleton生命周期作用域是默认的)。 如果引用的是'spring-beans-2.0.dtd' DTD或者是Spring 2.0 XSD schema,那么需要使用"scope"属性(因为"singleton"属性被删除了,新的DTD和XSD文件使用"scope"属性)。 简单地说,如果你用"singleton"属性那么就必须在那个文件里引用'spring-beans.dtd' DTD。 如果你用"scope"属性那么必须 在那个文件里引用'spring-beans-2.0.dtd' DTD 或'spring-beans-2.0.xsd' XSD。 |
[html]
view plain
copy
print?
<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/>
或者
<beanidbeanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/>
<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/> 或者 <beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/>
3. 其他作用域
其他作用域,即request、session以及globalsession仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架)。
Note | |
下面介绍的作用域仅仅在使用基于web的Spring ApplicationContext实现(如XmlWebApplicationContext)时有用。如果在普通的Spring IoC容器中,比如像XmlBeanFactory或ClassPathXmlApplicationContext,尝试使用这些作用域,你将会得到一个IllegalStateException异常(未知的bean作用域)。 |
3.1. 初始化web配置
要使用request、session和 globalsession作用域的bean(即具有web作用域的bean),在开始设置bean定义之前,还要做少量的初始配置。请注意,假如你只想要“常规的”作用域,也就是singleton和prototype,就不需要这一额外的设置。
在目前的情况下,根据你的特定servlet环境,有多种方法来完成这一初始设置。如果你使用的是Servlet
2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可
org.springframework.web.context.request.RequestContextListener
即:
[html]
view plain
copy
print?
web-app>
...
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
</web-app>
web-app> ... <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> ... </web-app>
如果你用的是早期版本的web容器(Servlet 2.4以前),那么你要使用一个javax.servlet.Filter的实现。请看下面的web.xml配置片段:
requestContextFilter
org.springframework.web.filter.RequestContextFilter
requestContextFilter
/*
即:
[html]
view plain
copy
print?
<web-app>
..
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
<web-app> .. <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ... </web-app>
3.2. Request作用域
考虑下面bean定义:针对每次HTTP请求,Spring容器会根据loginAction
bean定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction
bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。
[html]
view plain
copy
print?
<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>
<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>
3.3. Session作用域
考虑下面bean定义:针对某个HTTP Session,Spring容器会根据userPreferences
bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,你可以根据需要放心的更改所创建实例的内部状态,而别的HTTP
Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP
Session作用域内的bean也会被废弃掉。
[html]
view plain
copy
print?
<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>
<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>
3.4. global session作用域
考虑下面bean定义:global session作用域类似于标准的HTTP
Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet
web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet
Session的生命周期范围内。
请注意,假如你在编写一个标准的基于Servlet的web应用,并且定义了一个或多个具有global
session作用域的bean,系统会使用标准的HTTP Session作用域,并且不会引起任何错误。
[html]
view plain
copy
print?
<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>
<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>
3.5. 作用域bean与依赖
能够在HTTP request或者Session(甚至自定义)作用域中定义bean固然很好,但是SpringIoC容器除了管理对象(bean)的实例化,同时还负责协作者(或者叫依赖)的实例化。如果你打算将一个Http request范围的bean注入到另一个bean中,那么需要注入一个AOP代理来替代被注入的作用域bean。也就是说,你需要注入一个代理对象,该对象具有与被代理对象一样的公共接口,而容器则可以足够智能的从相关作用域中(比如一个HTTP
request)获取到真实的目标对象,并把方法调用委派给实际的对象。
不能和作用域为singleton或prototype的bean一起使用。为singleton bean创建一个scoped proxy将抛出BeanCreationException异常。 |
4.引入简单singleton实例:
配置文件:spring-relation.xml[html]
view plain
copy
print?
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
default-autowire="byName" default-lazy-init="true">
<!-- 使用bean的scope属性来配置bean的作用域
singleton:默认值,容器初始化时创建bean实例,在整个容器的生命周期内只创建这一个bean,单例的
prototype:一个bean定义对应多个对象实例。
request:在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。f
global session:在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。 -->
<bean id="car" scope="singleton" class="com.zd.runsharing.maven.springAutowire.Car">
<property name="brand" value="宝马啊汽车品牌"></property>
<property name="price" value="43000000"></property>
</bean>
</beans>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" default-autowire="byName" default-lazy-init="true"> <!-- 使用bean的scope属性来配置bean的作用域 singleton:默认值,容器初始化时创建bean实例,在整个容器的生命周期内只创建这一个bean,单例的 prototype:一个bean定义对应多个对象实例。 request:在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。 session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。f global session:在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。 --> <bean id="car" scope="singleton" class="com.zd.runsharing.maven.springAutowire.Car"> <property name="brand" value="宝马啊汽车品牌"></property> <property name="price" value="43000000"></property> </bean> </beans>
Car类:
[java]
view plain
copy
print?
public class Car {
public Car() {
System.out.println("Car .. constractor....");
}
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
}
public class Car { public Car() { System.out.println("Car .. constractor...."); } private String brand; private double price; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Car [brand=" + brand + ", price=" + price + "]"; } }主函数测试类:
[java]
view plain
copy
print?
public class BeanRelationMainTest {
public static void main(String[] args) {
ApplicationContext atx = new ClassPathXmlApplicationContext("spring-relation.xml");
Car car = (Car) atx.getBean("car");
Car car2 = (Car) atx.getBean("car");
System.out.println(car == car2);
}
}
public class BeanRelationMainTest { public static void main(String[] args) { ApplicationContext atx = new ClassPathXmlApplicationContext("spring-relation.xml"); Car car = (Car) atx.getBean("car"); Car car2 = (Car) atx.getBean("car"); System.out.println(car == car2); } }
运行结果:
=================================================================================
=================================================================================
=================================================================================
相关文章推荐
- spring中bean的scope
- 详解Spring中bean的scope singleton prototype request...
- Spring Bean Scope
- spring bean scope 的几种类型
- 【Spring】Spring IOC原理及源码解析之scope=request、session
- org.springframework.beans.factory.BeanCreationException: Scope 'request' is not active for the current thread
- spring中scope作用域(转)
- spring中scope作用域(转)
- Spring注入非单例bean以及scope的作用范围
- Spring scope属性详解
- Spring的scope属性
- Spring Bean scopes
- Spring Bean Scope Example using @Scope Annotation
- Spring scope属性详解
- Spring bean scopes
- spring中的单例多例——scope
- Spring面试题之神奇的scope的作用域
- Spring中bean中scope属性的意义
- Spring的scope属性
- spring(4)_ bean属性 scope:作用域和lazy-init