我相信我们每个人都有网上购物的经历,当我们进入购物网站的时候,比如京东,我们的账户里面就会有一个购物车,但是这个购物车是哪来的呢,或者我们在其他地方再次登陆的时候,是不是同一个购物车呢? 答案是肯定的,那他是怎么做到的呢,有机智的小伙伴可能会说,可以创建一个session,或者cookie,只要是同一个会话,他们就是同一个购物车,说的很对,我们可以创建一个会话生命周期的购物车,但我们知道,整个网站是一直在运行的,我们可以理解他为单例生命周期,而购物车我们可以理解为会话生命周期,对于单例和会话两个不同的生命周期的bean,我们应该怎样耦合呢,下面我们给出我们的答案。
@Component
public classs StoreService{
@Autowired
public void setShoppingCart(ShoppingCart shoppingCart){
this.shoppingCart = shoppingCart;
}
}
我们把一个网站服务定义为@Bean StoreService 他是单例的,会在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。
如图所示,Spring在处理单例生命周期和个会话生命周期时,可以采用如图所示基于代理的方式,代理是整个应用中一直存在的,所以他可以跟我们的单例@Bean StoreService 进行交流, 同时代理又暴露了与会话生命周期@Bean ShoppingCart 连接点,基于Spring的动态代理模式。.
生成代理的方式有两种 如果ShoppingCart 是接口的话,可以使用基于JDK的动态代理,如果是类的话,可以用CGlib代理,但这些Spring早就帮我们实现好了,我们只需要在我们的Spring.xml中声明<aop:scoped-proxy ??>配置即可。
这是一种解决单例与非单例生命周期矛盾的一种方法,如果大家有什么好的思路,可以在下面发表评论一起交流,千里之行,始于足下, 思考每一个细节,让自己的代码变得简单而又稳定,这将对你的应用产生意想不到的优化。