在默认的情况下,Spring应用上下文中所有的bean都是单例模式.
但是有时候,我们并不希望我们的bean是单例的,所以,spring提供了多种作用于,包括:
1. 单例(Singleton):在整个应用中,只创建一个bean实例
2. 原型(Prototype):每次注入或者通过Spring应用上下文获取时,都会创建一个新的实例
3. 会话(Session):在web应用中,每一个新的会话都会创建一个新的实例
4. 请求(Request):在web应用中,每一个新的请求都会创建一个新的实例
用Java配置的方法声明bean的作用域主要是通过@Scope注解,例如:
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MyBean{}
或者使用@Scope(value = "prototype"),上面的ConfigurableBeanFactory.SCOPE_PROTOTYPE也就是说prototype.
如果使用XML配置的话,可以这样做:
<bean id="myBean" class="xxx.xxx.MyBean" scope="prototype"/>
在使用session和request作用域的时候,我们可能会遇到这样一个问题,比如A类的scope是session,假设我们要将A注入到单例的B类中.
这时,spring在创建应用上下文的时候A类并没有被创建,因为A类要某个用户进入系统,创建了会话之后才会创建实例.所以无法将A注入到B.
另外,如果系统中有多个A类实例,我们并不想让spring注入某个固定的实例,我们希望使用的实例是当前会话的.
注:request同样存在这种问题.
这个时候,我们就需要使用scope的proxyMode属性.这个时候也要分两种情况,如果A类是一个接口的话,我们可以基于接口进行代理:
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION,
proxyMode = ScopedProxyMode.INTERFACES)
public interface A{...}
或
<bean id="a" class="xxx.xxx.A" scope="prototype">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
如果A是具体的类,我们应该这样声明:
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION,
proxyMode = ScopedProxyMode.TARGET_CLASS)
public interface A{...}
或
<bean id="a" class="xxx.xxx.A" scope="prototype">
<aop:scoped-proxy />
</bean>