bean的作用域
默认情况下Spring应用上下文中所有bean都是作为以单例的形式创建的,不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例
Spring定义的bean的作用域
- 单例(Singleton) : 整个应用中只创建bean的一个实例
原型(Prototype) : 每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例
会话(Session) : 在Web应用中,为每个会话创建一个bean实例
(如购物车bean)- 请求(Request) : 在Web应用中,为每个请求创建一个bean实例
用@Scope选择其他作用域
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad{...}
显示配置时
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Notepad notepad(){
return new Notepad();
}
xml配置时
<bean id="notepad" class = "..."
scope="prototype" />
在Web应用中使用会话和请求作用域
@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedroxyMode.INTERFACES)
public ShoppingCart cart(){...}
proxyMode=ScopedroxyMode.INTERFACES解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题
例如
@Component
public class StoreService{
@Autowired
public void setShoppingCart(ShoppingCart shoppingCart){
this.shoppingCart = shoppingCart;
}
}
等到某个用户进入系统创建了会话之后,才会出现ShoppingCart实例
Spring并不会将实际的ShoppingCart注入到StoreService中,而会注入一个ShoppingCart bean的代理,该代理暴露与SHoppingCart相同的方法,当StoreService调用ShoppingCart的方法的时候,代理会对其进行解析并将调用委托给会话作用域内真正的ShopingCart bean
proxyMode=ScopedroxyMode.INTERFACES 这表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean
如果SHoppingCart是接口而不是类的话用INTERFACES是可以的,如果是类,则proxyMode属性设置为ScopedProxyMode.TARGET_CLASS
在xml中声明作用域代理
使用<aop:...>要声明命名空间
<beans ....
xmlns:aop="http://www.springframework.org/schema/aop"
...
>
<bean id="cart" class="..."
scope="session">
<aop:scoped-proxy />
</bean>
<aop:scoped-proxy > 是与@Scope注解的proxyMode属性功能相同的xml配置元素
默认情况下他会使用CGLib创建目标类的代理
我们可以将其 proxy-target-class 属性设为false,要求其生成基于接口的代理
<aop:scoped-proxy proxy-target-class="false" />