J2EE开发者,对购物车这个概念太熟悉了。存在于Session周期中。今天就说说,如果用Spring管理购物车,怎么处理。

  1. 使用场景


    

必须要声明 

或者 annotation配置

@Scope(value="session",proxyMode= ScopedProxyMode.TARGET_CLASS)
@Component
public class Cart implements Serializable {
...
}

经过上面的配置,就可以在controller中,注入使用了。

接下来,分析spring是如何管理购物车的.

2. 源码分析

2.1 ScopedProxyFactoryBean 类图

AOP 工厂对象之ScopedProxyFactoryBean 原理解析_第1张图片

既然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());
}

AOP 工厂对象之ScopedProxyFactoryBean 原理解析_第2张图片

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;
      }
   }
   ...
  }