Spring IOC 之Bean的作用域
来源:互联网 发布:apache 二级域名配置 编辑:程序博客网 时间:2024/05/18 01:17
在默认情况下,Spring的应用上下文中所有的bean都是单例的形式创建的。也就是说,不管给定的一个bean被注入到其它bean多少次,每次注入的都是同一个实例。
在大多数情况下,单例bean是非常理想的方案。初始化和垃圾回收对象实例所带来的成本只留给一些小规模任务,在这些任务中,让对象保持无状态并且在应用中反复重用这些对象可能并不合理。
有时候你所使用的类可能是易变的,它们会保持一些状态,比如我们在Web购物商城中常见的购物车功能,不同的用户不可能同时使用同一个购物车实例,因此重用是不安全的。
(一)Spring中的作用域
Spring提供了多种作用域,可以基于这些作用域来创建bean,包括:
- 单例(Singleton):在整个应用中,只创建bean的一个实例;
- 原型(Prototype):每次注入或者通过Spring上下文获取的时候,都会创建一个新的bean实例;
- 会话(Session):在Web应用中,为每个会话创建一个bean实例;
- 请求(Request):在Web应用中,为每次请求创建一个bean实例;
如果需要自定义bean的作用域,需要使用@Scope注解,他可以与@Component或@Bean组合使用:
@Component@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)public class Cake implements Dessert {}
这里使用ConfigurableBeanFactory类的SCOPE_PROTOTYPE常亮设置为原型作用域。当然你也可以使用下面这种方式:
@Component@Scope("prototype")public class Cake implements Dessert {}
但是尽可能使用ConfigurableBeanFactory.SCOPE_PROTOTYPE,这更不容易出错。
当然也可以在Java配置中将作用域设置为原型bean,例如:
@Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Dessert cake(){ return new Cake(); }
同样,也可以在XML中配置,应用<bean>元素的scope属性:
<bean id="cake" class="cn.javacodes.spring.beans.Cake" scope="prototype"></bean>
(二)使用会话和请求作用域
在Web应用中,我们经常需要操作两种作用域:会话和请求。
就像前面所说,在购物商城的购物车实例上,单例和原型作用域自然不能满足我们的需求,我们希望为每一个会话都创建一个购物车,那么这里会话作用域就是最完美的选择。
下面来简单模拟一下购物车的作用域场景:
@Bean @Scope( value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.INTERFACES) public ShoppingCart cart(){ // .... }
这里,将value值设置成了WebApplicationContext中的SCOPTE_SESSION常量(值为session)。这会告诉Spring为Web应用中的每个会话创建一个ShoppingCart。对于每一个会话来说,这个bean实际上相当于是单例的。
这里需要注意,@Scope还有一个proxyMode属性,它被设置为ScopedProxyMode.INTERFACES。我们先不考虑这个属性,先来理解一下对Spring作用域的理解。
现在假设我们要将ShoppingCart bean注入到单例StoreService bean的Setter中,如下所示:
@Componentpublic class StoreService { private ShoppingCart shoppingCart ; @Autowired public void setShoppingCart(ShoppingCart shoppingCart){ this.shoppingCart = shoppingCart; }}
因为StoreService是一个单例bean,会在Spring上下文加载的时候创建,当它创建的时候,Spring会试图将ShoppingCart bean注入到setShoppingCart()方法中。但是ShoppingCart bean是会话作用域的,此时并不存在。直到某个用户进入系统,创建了会话以后,才会出现ShoppingCart实例。
另外,系统中将会存在多个ShoppingCart实例:每个用户一个。我们并不想让Spring注入到某个胡定的ShoppingCart实例到StoreService中。我们希望的是当StoreService处理购物车功能时,它所使用的ShoppingCart实例恰好是当前会话所对应的那一个。
Spring并不会将实际的ShoppingCart bean注入到StoreService中,Spring会注入一个到ShoppingCart bean的代理。这个代理会暴露与ShoppingCart相同的方法,所以StoreService会认为他就是一个购物车。但是,当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给作用域内真正的ShoppingCart bean。如下图所示:
现在我们来讨论一下proxyMode属性。我们将proxyMode属性设置为了ScopedProxyMode.INTERFACES,这表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean。
这里我们的ShoppingCart是接口而不是具体的类,这当然是可以的(也是最理想的代理模式)。但如果ShoppingCart是具体的实现类而不是接口的话,Spring就没办法创建基于接口的代理了。此时必须使用CGLib来生成基于类的代理。所以,如果bean类型是具体的类的话,我们必须要将proxyMode设置为ScopedProxyMode.TARGET_CLASS,以此来表明要以生成目标类扩展的方式创建代理。
请求作用域与会话作用域十分类似,也应该以作用域代理的方式进行注入,再次不做赘述。
(三)在XML中声明作用域代理
在XML中设置作用域代理需要使用Spring aop命名空间的一个元素:
<bean id="cart" class="cn.javacodes.spring.beans.ShoppingCart" scope="session"> <aop:scoped-proxy /> </bean>
当然了,在使用aop命名空间之前一定要在xml的顶部进行对命名空间进行声明:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> ......</beans>
注意:在使用Spring开发web项目时,需要在web.xml中加入如下内容(web2.4以上):
<web-app> ... <listener><listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> ...</web-app>
web 2.4以下版本需要加入:
<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>
另外,<aop:scoped-proxy />是与@Scope注解的proxyMode属性功能相同的Spring XML配置元素。它会告诉Spring为bean创建一个作用域代理。默认情况下,它会使用CGLib创建目标类的代理。但是我们也可以将proxy-target-class属性设置为false,进而要求它生成基于接口的代理:
<bean id="cart" class="cn.javacodes.spring.beans.ShoppingCart" scope="session"> <aop:scoped-proxy proxy-target-class="false"/> </bean>
0 0
- Spring IOC 之Bean的作用域
- Spring IOC bean 的作用域
- Spring--IoC--Bean的装配--Bean的作用域
- spring之bean的作用域scope
- Spring之Bean的作用域
- 第二章 IoC Bean的作用域
- spring学习总结(六):IOC & DI 配置Bean之作用域、加载外部属性文件、SPEL
- Spring IOC学习心得之Bean对IOC容器的感知
- 【Java.Spring.Core】【IoC】Bean 作用域 - Scopes
- Spring-IoC的简单使用及bean的作用域属性
- 【spring教程之四】spring中bean的作用域
- Spring之旅--Spring管理bean的作用域
- spring的入门(aop,ioc,bean作用域等)简介
- 深入解读Spring Framework IoC容器(第六弹:Bean的作用域)
- 深入解读Spring Framework IoC容器(第七弹:不同作用域Bean的依赖)
- Spring学习笔记-IOC高级特性1-Bean的创建、作用域、初始化和析构
- spring bean的作用域
- spring bean的作用域
- webstorm 2017 激活破解
- java.lang.ClassNotFoundException(MyEclipse引入jar包找不到类的解决)
- mac配置tomcate时出现Permission denied
- SpringMVC 整合Jackson报错
- IP、子网掩码、网络号之间的关系、区分和运算
- Spring IOC 之Bean的作用域
- Oracle中临时表空间的清理
- DELL存储提示虚拟磁盘不在首选路径上处理方法
- String,StringBuilder,StringBuffer之间的区别
- 抓取新浪微博好友昵称和性别
- queue_runner_impl.py
- 一天搞定HTML----常用标签01
- 获取url参数以及出现乱码
- Regular Expression Syntax