AOP 工廠對象之ScopedProxyFactoryBean 原理解析

J2EE開發者,對購物車這個概念太熟悉了。存在於Session週期中。今天就說說,如果用Spring管理購物車,怎麼處理。

  1. 使用場景

<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 類圖

wKiom1kll8HA0NngAABh4fY4Bco101.png-wh_50

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

wKiom1klmWShMzUnAACIPLreQUs791.png

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章