J2EE開發者,對購物車這個概念太熟悉了。存在于Session周期中。今天就說說,如果用Spring管理購物車,怎麼處理。
使用場景
1
2
3
<code><</code><code>bean</code> <code>id</code><code>=</code><code>"cart"</code> <code>class</code><code>=</code><code>"com.hellojd.jpetstore.domain.model.Cart"</code> <code>scope</code><code>=</code><code>"session"</code><code>></code>
<code> </code><code><</code><code>aop:scoped-proxy</code> <code>proxy-target-class</code><code>=</code><code>"true"</code><code>/></code>
<code></</code><code>bean</code><code>></code>
必須要聲明 <aop:scoped-proxy..>
或者 annotation配置
4
5
<code>@Scope</code><code>(value=</code><code>"session"</code><code>,proxyMode= ScopedProxyMode.TARGET_CLASS)</code>
<code>@Component</code>
<code>public</code> <code>class</code> <code>Cart </code><code>implements</code> <code>Serializable {</code>
<code>...</code>
<code>}</code>
經過上面的配置,就可以在controller中,注入使用了。
接下來,分析spring是如何管理購物車的.
2. 源碼分析
2.1 ScopedProxyFactoryBean 類圖
<a href="https://s2.51cto.com/wyfs02/M00/96/D0/wKiom1kll8HA0NngAABh4fY4Bco101.png-wh_500x0-wm_3-wmp_4-s_3511243032.png" target="_blank"></a>
既然ScopedProxyFactoryBean,是個FactoryBean,就關注下getObject()
6
<code>public</code> <code>Object getObject() {</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.proxy == </code><code>null</code><code>) {</code>
<code> </code><code>throw</code> <code>new</code> <code>FactoryBeanNotInitializedException();</code>
<code> </code><code>}</code>
<code> </code><code>return</code> <code>this</code><code>.proxy;</code>
重點是proxy屬性的維護了。在BeanFactoryAware.setBeanFactory接口方法中初始化。
發生時機:普通屬性注入之後,InitializingBean.afterPropertiesSet() 和 custom init-method之前
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<code>public</code> <code>void</code> <code>setBeanFactory(BeanFactory beanFactory) {</code>
<code> </code><code>if</code> <code>(!(beanFactory </code><code>instanceof</code> <code>ConfigurableBeanFactory)) {</code>
<code> </code><code>throw</code> <code>new</code> <code>IllegalStateException(</code><code>"Not running in a ConfigurableBeanFactory: "</code> <code>+ beanFactory);</code>
<code> </code><code>ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;</code>
<code> </code><code>this</code><code>.scopedTargetSource.setBeanFactory(beanFactory);</code>
<code> </code><code>ProxyFactory pf = </code><code>new</code> <code>ProxyFactory();</code>
<code> </code><code>pf.copyFrom(</code><code>this</code><code>);</code>
<code> </code><code>pf.setTargetSource(</code><code>this</code><code>.scopedTargetSource);</code>
<code> </code><code>Class beanType = beanFactory.getType(</code><code>this</code><code>.targetBeanName);</code>
<code> </code><code>if</code> <code>(beanType == </code><code>null</code><code>) {</code>
<code> </code><code>throw</code> <code>new</code> <code>IllegalStateException(</code><code>"Cannot create scoped proxy for bean '"</code> <code>+ </code><code>this</code><code>.targetBeanName +</code>
<code> </code><code>"': Target type could not be determined at the time of proxy creation."</code><code>);</code>
<code> </code><code>if</code> <code>(!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {</code>
<code> </code><code>//設定源接口</code>
<code> </code><code>pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));</code>
<code> </code><code>// 為增加DefaultScopedObject能力,增加introduction </code>
<code> </code><code>ScopedObject scopedObject = </code><code>new</code> <code>DefaultScopedObject(cbf, </code><code>this</code><code>.scopedTargetSource.getTargetBeanName());</code>
<code> </code><code>pf.addAdvice(</code><code>new</code> <code>DelegatingIntroductionInterceptor(scopedObject));</code>
<code> </code><code>// Add the AopInfrastructureBean marker to indicate that the scoped proxy</code>
<code> </code><code>// itself is not subject to auto-proxying! Only its target bean is.</code>
<code> </code><code>pf.addInterface(AopInfrastructureBean.</code><code>class</code><code>);</code>
<code> </code><code>this</code><code>.proxy = pf.getProxy(cbf.getBeanClassLoader());</code>
<a href="https://s2.51cto.com/wyfs02/M02/96/D0/wKiom1klmWShMzUnAACIPLreQUs791.png" target="_blank"></a>
TargetSource
用于擷取AOP調用的目前“目标”
Target
AbstractBeanFactoryBasedTargetSource
基于Spring BeanFactory的實作TargetSource的基類
ProxyConfig
友善的用于建立代理的超類配置
AOP
ProxyFactory
程式設計式AOP代理工廠
ProxyCreatorSupport
代理工廠的基類
AdvisedSupport
代理配置元資訊管理基類AOP
AopProxyFactory
建立AOP代理的工廠
ScopedObject
用于範圍對象的AOP接口
完成從spring中擷取
DelegatingIntroductionInterceptor
委托引入攔截器
3.RequestScope VS SessionScope
<code>public</code> <code>class</code> <code>SessionScope </code><code>extends</code> <code>AbstractRequestAttributesScope {</code>
<code> </code><code>public</code> <code>String getConversationId() {</code>
<code> </code><code>return</code> <code>RequestContextHolder.currentRequestAttributes().getSessionId();</code>
<code> </code><code>}</code>
<code> </code><code>@Override</code>
<code> </code><code>public</code> <code>Object get(String name, ObjectFactory objectFactory) {</code>
<code> </code><code>Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();</code>
<code> </code><code>synchronized</code> <code>(mutex) {</code>
<code> </code><code>return</code> <code>super</code><code>.get(name, objectFactory);</code>
<code> </code><code>}</code>
<code> </code><code>public</code> <code>Object remove(String name) {</code>
<code> </code><code>return</code> <code>super</code><code>.remove(name);</code>
<code> </code><code>...</code>
<code>} </code>
or
<code>public</code> <code>abstract</code> <code>class</code> <code>AbstractRequestAttributesScope </code><code>implements</code> <code>Scope {</code>
<code> </code><code>public</code> <code>Object get(String name, ObjectFactory objectFactory) {</code>
<code> </code><code>RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();</code>
<code> </code><code>Object scopedObject = attributes.getAttribute(name, getScope());</code>
<code> </code><code>if</code> <code>(scopedObject == </code><code>null</code><code>) {</code>
<code> </code><code>scopedObject = objectFactory.getObject();</code>
<code> </code><code>attributes.setAttribute(name, scopedObject, getScope());</code>
<code> </code><code>}</code>
<code> </code><code>return</code> <code>scopedObject;</code>
<code> </code><code>public</code> <code>Object remove(String name) {</code>
<code> </code><code>if</code> <code>(scopedObject != </code><code>null</code><code>) {</code>
<code> </code><code>attributes.removeAttribute(name, getScope());</code>
<code> </code><code>return</code> <code>scopedObject;</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>return</code> <code>null</code><code>;</code>
<code> </code><code>...</code>
<code> </code><code>}</code>
<code></code>
本文轉自 randy_shandong 51CTO部落格,原文連結:http://blog.51cto.com/dba10g/1929157,如需轉載請自行聯系原作者