作用域
<!-- bean的作用域:singleton、prototype,默认情况下是singleton的
singleton:在容器启动完成之前就已经创建好对象,获取的所有对象都是同一个。
prototype:容器启动的时候不会创建bean,只有在获取对象的时候才会创建该对象,每次创建都是一个新的对象 -->
<bean id="person1" class="com.nanborone.bean.Person" scope="prototype">
<property name="id" value="1"/>
<property name="name" value="nanborone"/>
<property name="male" value="true"/>
</bean>
Spring容器会在容器创建的时候针对每一个Bean进行校验,但是Bean的属性在Bean没有真正创建之前是不会进行配置的。单例类型的Bean是容器创建的时候配置成预实例状态的, 其他的Bean都只有在请求的时候,才会创建。
如果开发者主要使用基于构造函数的依赖注入,或者每个bean的作用域都是prototype,那么很有可能出现循环依赖的情况,并且抛出BeanCurrentlyInCreationException
。
代理作用域
将一个多例的bean B注入到单例bean A时,由于容器启动时装配已经完成,则在使用时通过A每次获得的B其实都是一个实例,失去了多例的作用,可以通过代理作用域的方式实现。
<!-- 在根标签下添加xmlns:aop="http://www.springframework.org/schema/aop" -->
<!-- xsi:schemaLocation中加入http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd -->
<bean id="person1" name="person" class="com.nanborone.bean.Person" >
<property name="address" ref="address"/>
</bean>
<!-- 将短周期作用域bean注入到长周期作用域bean,通过创建代理的方式实现 -->
<bean id="address" class="com.nanborone.bean.Address" scope="prototype">
<!-- proxy-target-class:设置为false时启用JDK代理,默认CGLIB代理 -->
<aop:scoped-proxy/>
</bean>
自定义作用域
定义作用域对象
实现Scope接口并实现方法。
Scope
接口有四个方法用于操作对象,例如获取、移除或销毁等操作。
以下方法返回相应作用域的对象,如果它不存在,那么将会返回绑定该作用域的新实例
Object get(String name, ObjectFactory objectFactory)
以下方法从相应作用域中删除对象,删除的对象作为返回值,无法找到对象时返回null
Object remove(String name)
以下方法注册在销毁时或在Scope中的指定对象被销毁时应该执行的回调:
void registerDestructionCallback(String name, Runnable destructionCallback)
以下方法获取相应作用域的区分标识符:
String getConversationId()
通过编程来注册作用域
示例使用SimpleThreadScope,这个例子在Spring中是有实现的,但没有默认注册。
您自定义的作用域也可以通过如下的方式来注册。
Scope simpleThreadScope = new SimpleThreadScope();
// 在Spring容器中注册新Scope,第一个参数是作用域名称,第二个参数是作用域实现对象
context.getBeanFactory().registerScope("thread", simpleThreadScope);
然后,您可以创建符合自定义Scope的作用域规则的bean定义,如下所示:
<bean id="..." class="..." scope="thread">
通过配置来注册作用域
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
<bean id="person" class="com.nanborone.bean.Person">
<property name="id" value="1"/>
<property name="name" value="nanborone"/>
<property name="male" value="true"/>
<property name="address" ref="address"/>
</bean>
<bean id="address" class="com.nanborone.bean.Address" scope="thread" >
<property name="province" value="辽宁"/>
<property name="city" value="沈阳"/>
<property name="town" value="浑南"/>
<aop:scoped-proxy/>
</bean>