当你创建一个bean
的定义时候,你可以创建一个模版(recipe)通过bean
定义的类定义去创建一个真实的实例。bean
定义是模版(recipe)的概念很重要,因为这意味着,与使用类一样,你可以从一个模版(recipe)创建多个对象实例。
你不仅可以控制要插入到从特定bean
定义创建的对象中的各种依赖项和配置值,还可以控制从特定bean
定义创建的对象的作用域。这种方法是非常有用的和灵活的,因为你可以选择通过配置创建的对象的作用域,而不必在Java类级别上考虑对象的作用域。bean
能够定义部署到一个或多个作用域。Spring
框架支撑6种作用域,4种仅仅使用web
环境。你可以创建定制的作用域。
下面的表格描述了支撑的作用域:
从Spring3.0
后,线程安全作用域是有效的但默认没有注册。更多的信息,查看文档 SimpleThreadScope
。更多关于怎样去注册和自定义作用域,查看自定义作用域
1.5.1 单例bean作用域
单例bean
仅仅只有一个共享实例被容器管理,并且所有对具有与该bean
定义相匹配的ID
的bean
的请求都会导致该特定bean
实例被Spring
容器返回。换一种方式,当你定义一个bean
的定义并且它的作用域是单例的时候,Spring IoC
容器创建通过bean
定义的对象定义的实例。这个单例存储在缓存中,并且对命名bean
的所有请求和引用返回的是缓存对象。下面图片展示了单例bean
作用域是怎样工作的:
Spring
的单例bean
概念与在GoF
设计模式书中的单例模式不同。GoF
单例硬编码对应的作用域例如:只有一个特定类的对象实例对每一个ClassLoader
只创建一个对象实例。最好将Spring
单例的范围描述为每个容器和每个bean
(备注:GoF
设计模式中的单例bean
是针对不同ClassLoader
来说的,而Spring
的单例是针对不同容器级别的)。这意味着,如果在单个Spring
容器对指定类定义一个bean
,Spring
容器通过bean
定义的类创建一个实例。在Spring
中单例作用域是默认的。在XML中去定义一个bean
为单例,你可以定义一个bean
类似下面例子:
<bean id="accountService" class="com.something.DefaultAccountService"/>
<!-- 通过scope指定bean作用域 单例:singleton ,原型:prototype-->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
1.5.2 原型作用域
非单例原型bean
的作用域部署结果是在每一次请求指定bean
的时候都会创建一个bean
实例。也就是,bean
被注入到其他bean
或在容器通过getBean()
方法调用都会创建一个新bean
。通常,为所有的无状态bean使用原型作用域并且有状态bean
使用单例bean
作用域。
下面的图说明Spring
的单例作用域:
数据访问对象(DAO
)通常不被配置作为一个原型,因为典型的DAO
不会维持任何会话状态。我们可以更容易地重用单例图的核心。
下面例子在XML
中定义一个原型bean
:
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
与其他作用域对比,Spring
没有管理原型bean
的完整生命周期。容器将实例化、配置或以其他方式组装原型对象,然后将其交给客户端,无需对该原型实例的进一步记录。因此,尽管初始化生命周期回调函数在所有对象上被回调而不管作用域如何,在原型情况下,配置销毁生命周期回调是不被回调。客户端代码必须清除原型作用域内的对象并释放原型Bean
占用的昂贵资源。为了让Spring
容器释放原型作用域bean
所拥有的资源,请尝试使用自定义bean
的post-processor后置处理器,该后处理器包含对需要清理的bean
的引用(可以通过后置处理器释放引用资源)。
在某些方面,Spring
容器在原型范围内的bean
角色是Java new
运算符的替代。所有超过该点的生命周期管理都必须由客户端处理。(更多关于在Spring
容器中的bean
生命周期,查看生命周期回调)
1.5.3 单例bean与原型bean的依赖
当你使用依赖于原型bean
的单例作用域bean
时(单例引用原型bean
),需要注意的是这些依赖项在初始化时候被解析。因此,如果你依赖注入一个原型bean
到一个单例bean
中,一个新原型bean
被初始化并且依赖注入到一个单例bean
。原型实例是唯一一个被提供给单例作用域bean
的实例。(备注:单例引用原型bean