J2EE開發者,對購物車這個概念太熟悉了。存在於Session週期中。今天就說說,如果用Spring管理購物車,怎麼處理。
使用場景
<bean id="cart" class="com.hellojd.jpetstore.domain.model.Cart" scope="session"> <aop:scoped-proxy proxy-target-class="true"/> </bean>
必須要聲明 <aop:scoped-proxy..>
或者 annotation配置
@Scope(value="session",proxyMode= ScopedProxyMode.TARGET_CLASS) @Component public class Cart implements Serializable { ... }
經過上面的配置,就可以在controller中,注入使用了。
接下來,分析spring是如何管理購物車的.
2. 源碼分析
2.1 ScopedProxyFactoryBean 類圖
既然ScopedProxyFactoryBean,是個FactoryBean,就關注下getObject()
public Object getObject() { if (this.proxy == null) { throw new FactoryBeanNotInitializedException(); } return this.proxy; }
重點是proxy屬性的維護了。在BeanFactoryAware.setBeanFactory接口方法中初始化。
發生時機:普通屬性注入之後,InitializingBean.afterPropertiesSet() 和 custom init-method之前
public void setBeanFactory(BeanFactory beanFactory) { if (!(beanFactory instanceof ConfigurableBeanFactory)) { throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory); } ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory; this.scopedTargetSource.setBeanFactory(beanFactory); ProxyFactory pf = new ProxyFactory(); pf.copyFrom(this); pf.setTargetSource(this.scopedTargetSource); Class beanType = beanFactory.getType(this.targetBeanName); if (beanType == null) { throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName + "': Target type could not be determined at the time of proxy creation."); } if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) { //設置源接口 pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader())); } // 爲增加DefaultScopedObject能力,增加introduction ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName()); pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject)); // Add the AopInfrastructureBean marker to indicate that the scoped proxy // itself is not subject to auto-proxying! Only its target bean is. pf.addInterface(AopInfrastructureBean.class); this.proxy = pf.getProxy(cbf.getBeanClassLoader()); }
TargetSource | 用於獲取AOP調用的當前“目標” | Target |
AbstractBeanFactoryBasedTargetSource | 基於Spring BeanFactory的實現TargetSource的基類 | Target |
ProxyConfig | 方便的用於創建代理的超類配置 | AOP |
ProxyFactory | 編程式AOP代理工廠 | AOP |
ProxyCreatorSupport | 代理工廠的基類 | AOP |
AdvisedSupport | 代理配置元信息管理基類AOP | AOP |
AopProxyFactory | 創建AOP代理的工廠 | |
ScopedObject | 用於範圍對象的AOP接口 | |
DefaultScopedObject | 完成從spring中獲取 | |
DelegatingIntroductionInterceptor | 委託引入攔截器 | |
3.RequestScope VS SessionScope
public class SessionScope extends AbstractRequestAttributesScope { public String getConversationId() { return RequestContextHolder.currentRequestAttributes().getSessionId(); } @Override public Object get(String name, ObjectFactory objectFactory) { Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex(); synchronized (mutex) { return super.get(name, objectFactory); } } @Override public Object remove(String name) { Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex(); synchronized (mutex) { return super.remove(name); } } ... }
or
public abstract class AbstractRequestAttributesScope implements Scope { public Object get(String name, ObjectFactory objectFactory) { RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); Object scopedObject = attributes.getAttribute(name, getScope()); if (scopedObject == null) { scopedObject = objectFactory.getObject(); attributes.setAttribute(name, scopedObject, getScope()); } return scopedObject; } public Object remove(String name) { RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); Object scopedObject = attributes.getAttribute(name, getScope()); if (scopedObject != null) { attributes.removeAttribute(name, getScope()); return scopedObject; } else { return null; } } ... }