<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    The important thing in life is to have a great aim , and the determination

    常用鏈接

    統計

    IT技術鏈接

    保險相關

    友情鏈接

    基金知識

    生活相關

    最新評論

    Spring源代碼解析(五):Spring聲明式事務處理

    我們看看Spring中的事務處理的代碼,使用Spring管理事務有聲明式和編程式兩種方式,聲明式事務處理通過AOP的實現把事物管理代碼作為方面封裝來橫向插入到業務代碼中,使得事務管理代碼和業務代碼解藕。在這種方式我們結合IoC容器和Spirng已有的FactoryBean來對事務管理進行屬性配置,比如傳播行為,隔離級別等。其中最簡單的方式就是通過配置TransactionProxyFactoryBean來實現聲明式事物;
    在整個源代碼分析中,我們可以大致可以看到Spring實現聲明式事物管理有這么幾個部分:

        * 對在上下文中配置的屬性的處理,這里涉及的類是TransactionAttributeSourceAdvisor,這是一個通知器,用它來對屬性值進行處理,屬性信息放在TransactionAttribute中來使用,而這些屬性的處理往往是和對切入點的處理是結合起來的。對屬性的處理放在類TransactionAttributeSource中完成。
        * 創建事物的過程,這個過程是委托給具體的事物管理器來創建的,但Spring通過TransactionStatus來傳遞相關的信息。
        * 對事物的處理通過對相關信息的判斷來委托給具體的事物管理器完成。

    我們下面看看具體的實現,在TransactionFactoryBean中:
    Java代碼 復制代碼 收藏代碼
    1. public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean   
    2.         implements FactoryBean, BeanFactoryAware {   
    3. //這里是Spring事務處理而使用的AOP攔截器,中間封裝了Spring對事務處理的代碼來支持聲明式事務處理的實現   
    4.     private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();   
    5.   
    6.     private Pointcut pointcut;   
    7.   
    8. //這里Spring把TransactionManager注入到TransactionInterceptor中去   
    9.     public void setTransactionManager(PlatformTransactionManager transactionManager) {   
    10.         this.transactionInterceptor.setTransactionManager(transactionManager);   
    11.     }   
    12.   
    13. //這里把在bean配置文件中讀到的事務管理的屬性信息注入到TransactionInterceptor中去   
    14.     public void setTransactionAttributes(Properties transactionAttributes) {   
    15.         this.transactionInterceptor.setTransactionAttributes(transactionAttributes);   
    16.     }   
    17.   
    18.     .........中間省略了其他一些方法.......   
    19.   
    20.     //這里創建Spring AOP對事務處理的Advisor   
    21.     protected Object createMainInterceptor() {   
    22.         this.transactionInterceptor.afterPropertiesSet();   
    23.         if (this.pointcut != null) {   
    24.             //這里使用默認的通知器   
    25.             return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);   
    26.         }   
    27.         else {   
    28.             // 使用上面定義好的TransactionInterceptor作為攔截器,同時使用TransactionAttributeSourceAdvisor   
    29.             return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);   
    30.         }   
    31.     }   
    32. }  

    那什么時候Spring的TransactionInterceptor被注入到Spring AOP中成為Advisor中的一部分呢?我們看到在TransactionProxyFactoryBean中,這個方法在IOC初始化bean的時候被執行:
    Java代碼 復制代碼 收藏代碼
    1. public void afterPropertiesSet() {   
    2.     .......   
    3.     //TransactionProxyFactoryBean實際上使用ProxyFactory完成AOP的基本功能。   
    4.     ProxyFactory proxyFactory = new ProxyFactory();   
    5.   
    6.     if (this.preInterceptors != null) {   
    7.         for (int i = 0; i < this.preInterceptors.length; i++) {   
    8.             proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.preInterceptors[i]));   
    9.         }   
    10.     }   
    11.   
    12.     //這里是Spring加入通知器的地方   
    13.     //有兩種通知器可以被加入DefaultPointcutAdvisor或者TransactionAttributeSourceAdvisor   
    14.     //這里把Spring處理聲明式事務處理的AOP代碼都放到ProxyFactory中去,怎樣加入advisor我們可以參考ProxyFactory的父類AdvisedSupport()   
    15.     //由它來維護一個advice的鏈表,通過這個鏈表的增刪改來抽象我們對整個通知器配置的增刪改操作。   
    16.     proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));   
    17.   
    18.     if (this.postInterceptors != null) {   
    19.         for (int i = 0; i < this.postInterceptors.length; i++) {   
    20.             proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.postInterceptors[i]));   
    21.         }   
    22.     }   
    23.   
    24.     proxyFactory.copyFrom(this);   
    25.       
    26.     //這里創建AOP的目標源   
    27.     TargetSource targetSource = createTargetSource(this.target);   
    28.     proxyFactory.setTargetSource(targetSource);   
    29.   
    30.     if (this.proxyInterfaces != null) {   
    31.         proxyFactory.setInterfaces(this.proxyInterfaces);   
    32.     }   
    33.     else if (!isProxyTargetClass()) {   
    34.         proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass()));   
    35.     }   
    36.   
    37.     this.proxy = getProxy(proxyFactory);   
    38. }  

    Spring 已經定義了一個transctionInterceptor作為攔截器或者AOP advice的實現,在IOC容器中定義的其他屬性比如transactionManager和事務管理的屬性都會傳到已經定義好的 TransactionInterceptor那里去進行處理。以上反映了基本的Spring AOP的定義過程,其中pointcut和advice都已經定義好,同時也通過通知器配置到ProxyFactory中去了。
    下面讓我們回到TransactionProxyFactoryBean中看看TransactionAttributeSourceAdvisor是怎樣定義的,這樣我們可以理解具體的屬性是怎樣起作用,這里我們分析一下類TransactionAttributeSourceAdvisor:
    Java代碼 復制代碼 收藏代碼
    1. public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {   
    2.     //和其他Advisor一樣,同樣需要定義AOP中的用到的Interceptor和Pointcut   
    3.     //Interceptor使用傳進來的TransactionInterceptor   
    4.     //而對于pointcut,這里定義了一個內部類,參見下面的代碼     
    5.     private TransactionInterceptor transactionInterceptor;   
    6.   
    7.     private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut();   
    8.       
    9.     .........   
    10.     //定義的PointCut內部類   
    11.         private class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {   
    12.        .......   
    13.       //方法匹配的實現,使用了TransactionAttributeSource類   
    14.         public boolean matches(Method method, Class targetClass) {   
    15.             TransactionAttributeSource tas = getTransactionAttributeSource();   
    16.             //這里使用TransactionAttributeSource來對配置屬性進行處理   
    17.             return (tas != null && tas.getTransactionAttribute(method, targetClass) != null);   
    18.         }   
    19.     ........省略了equal,hashcode,tostring的代碼   
    20.     }  

    這里我們看看屬性值是怎樣被讀入的:AbstractFallbackTransactionAttributeSource負責具體的屬性讀入任務,我們可以有兩種讀入方式,比如annotation和直接配置.我們下面看看直接配置的讀入方式,在Spring中同時對讀入的屬性值進行了緩存處理,這是一個decorator模式:
    Java代碼 復制代碼 收藏代碼
    1. public final TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {   
    2.     //這里先查一下緩存里有沒有事務管理的屬性配置,如果有從緩存中取得TransactionAttribute   
    3.     Object cacheKey = getCacheKey(method, targetClass);   
    4.     Object cached = this.cache.get(cacheKey);   
    5.     if (cached != null) {   
    6.         if (cached == NULL_TRANSACTION_ATTRIBUTE) {   
    7.             return null;   
    8.         }   
    9.         else {   
    10.             return (TransactionAttribute) cached;   
    11.         }   
    12.     }   
    13.     else {   
    14.         // 這里通過對方法和目標對象的信息來計算事務緩存屬性   
    15.         TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);   
    16.         //把得到的事務緩存屬性存到緩存中,下次可以直接從緩存中取得。   
    17.         if (txAtt == null) {   
    18.             this.cache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);   
    19.         }   
    20.         else {   
    21.             ...........   
    22.             this.cache.put(cacheKey, txAtt);   
    23.         }   
    24.         return txAtt;   
    25.     }   
    26. }  

    別急,基本的處理在computeTransactionAttribute()中:
    Java代碼 復制代碼 收藏代碼
    1. private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) {   
    2.     //這里檢測是不是public方法   
    3.     if(allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {   
    4.         return null;   
    5.     }   
    6.       
    7.     Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);   
    8.       
    9.     // First try is the method in the target class.   
    10.     TransactionAttribute txAtt = findTransactionAttribute(findAllAttributes(specificMethod));   
    11.     if (txAtt != null) {   
    12.         return txAtt;   
    13.     }   
    14.   
    15.     // Second try is the transaction attribute on the target class.   
    16.     txAtt = findTransactionAttribute(findAllAttributes(specificMethod.getDeclaringClass()));   
    17.     if (txAtt != null) {   
    18.         return txAtt;   
    19.     }   
    20.   
    21.     if (specificMethod != method) {   
    22.         // Fallback is to look at the original method.   
    23.         txAtt = findTransactionAttribute(findAllAttributes(method));   
    24.         if (txAtt != null) {   
    25.             return txAtt;   
    26.         }   
    27.         // Last fallback is the class of the original method.   
    28.         return findTransactionAttribute(findAllAttributes(method.getDeclaringClass()));   
    29.     }   
    30.     return null;   
    31. }  

    經過一系列的嘗試我們可以通過findTransactionAttribute()通過調用findAllAttribute()得到TransactionAttribute的對象,如果返回的是null,這說明該方法不是我們需要事務處理的方法。
    在完成把需要的通知器加到ProxyFactory中去的基礎上,我們看看具體的看事務處理代碼怎樣起作用,在TransactionInterceptor中:
    Java代碼 復制代碼 收藏代碼
    1. public Object invoke(final MethodInvocation invocation) throws Throwable {   
    2.     //這里得到目標對象   
    3.     Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);   
    4.   
    5.     //這里同樣的通過判斷是否能夠得到TransactionAttribute來決定是否對當前方法進行事務處理,有可能該屬性已經被緩存,   
    6.     //具體可以參考上面對getTransactionAttribute的分析,同樣是通過TransactionAttributeSource   
    7.     final TransactionAttribute txAttr =   
    8.             getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);   
    9.     final String joinpointIdentification = methodIdentification(invocation.getMethod());   
    10.   
    11.     //這里判斷我們使用了什么TransactionManager   
    12.     if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {   
    13.         // 這里創建事務,同時把創建事務過程中得到的信息放到TransactionInfo中去   
    14.         TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);   
    15.         Object retVal = null;   
    16.         try {   
    17.               retVal = invocation.proceed();   
    18.         }   
    19.         catch (Throwable ex) {   
    20.             // target invocation exception   
    21.             completeTransactionAfterThrowing(txInfo, ex);   
    22.             throw ex;   
    23.         }   
    24.         finally {   
    25.             cleanupTransactionInfo(txInfo);   
    26.         }   
    27.         commitTransactionAfterReturning(txInfo);   
    28.         return retVal;   
    29.     }   
    30.   
    31.     else {   
    32.         // 使用的是Spring定義的PlatformTransactionManager同時實現了回調接口,我們通過其回調函數完成事務處理,就像我們使用編程式事務處理一樣。   
    33.         try {   
    34.             Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,   
    35.                     new TransactionCallback() {   
    36.                         public Object doInTransaction(TransactionStatus status) {   
    37.                             //同樣的需要一個TransactonInfo   
    38.                             TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);   
    39.                             try {   
    40.                                 return invocation.proceed();   
    41.                             }   
    42.                          .....這里省去了異常處理和事務信息的清理代碼   
    43.                     });   
    44.          ...........   
    45.     }   
    46. }  

    這里面涉及到事務的創建,我們可以在TransactionAspectSupport實現的事務管理代碼:
    Java代碼 復制代碼 收藏代碼
    1. protected TransactionInfo createTransactionIfNecessary(   
    2.         TransactionAttribute txAttr, final String joinpointIdentification) {   
    3.   
    4.     // If no name specified, apply method identification as transaction name.   
    5.     if (txAttr != null && txAttr.getName() == null) {   
    6.         txAttr = new DelegatingTransactionAttribute(txAttr) {   
    7.             public String getName() {   
    8.                 return joinpointIdentification;   
    9.             }   
    10.         };   
    11.     }   
    12.   
    13.     TransactionStatus status = null;   
    14.     if (txAttr != null) {   
    15.     //這里使用了我們定義好的事務配置信息,有事務管理器來創建事務,同時返回TransactionInfo   
    16.         status = getTransactionManager().getTransaction(txAttr);   
    17.     }   
    18.     return prepareTransactionInfo(txAttr, joinpointIdentification, status);   
    19. }  

    首先通過TransactionManager得到需要的事務,事務的創建根據我們定義的事務配置決定,在 AbstractTransactionManager中給出一個標準的創建過程,當然創建什么樣的事務還是需要具體的 PlatformTransactionManager來決定,但這里給出了創建事務的模板:
    Java代碼 復制代碼 收藏代碼
    1. public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {   
    2.     Object transaction = doGetTransaction();   
    3.     ......   
    4.   
    5.     if (definition == null) {   
    6.         //如果事務信息沒有被配置,我們使用Spring默認的配置方式   
    7.         definition = new DefaultTransactionDefinition();   
    8.     }   
    9.   
    10.     if (isExistingTransaction(transaction)) {   
    11.         // Existing transaction found -> check propagation behavior to find out how to behave.   
    12.         return handleExistingTransaction(definition, transaction, debugEnabled);   
    13.     }   
    14.   
    15.     // Check definition settings for new transaction.   
    16.     //下面就是使用配置信息來創建我們需要的事務;比如傳播屬性和同步屬性等   
    17.     //最后把創建過程中的信息收集起來放到TransactionStatus中返回;     
    18.     if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {   
    19.         throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());   
    20.     }   
    21.   
    22.     // No existing transaction found -> check propagation behavior to find out how to behave.   
    23.     if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {   
    24.         throw new IllegalTransactionStateException(   
    25.                 "Transaction propagation 'mandatory' but no existing transaction found");   
    26.     }   
    27.     else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||   
    28.             definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||   
    29.         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {   
    30.         //這里是事務管理器創建事務的地方,并將創建過程中得到的信息放到TransactionStatus中去,包括創建出來的事務   
    31.         doBegin(transaction, definition);   
    32.         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);   
    33.         return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);   
    34.     }   
    35.     else {   
    36.         boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);   
    37.         return newTransactionStatus(definition, nullfalse, newSynchronization, debugEnabled, null);   
    38.     }   
    39. }  

    接著通過調用prepareTransactionInfo完成事務創建的準備,創建過程中得到的信息存儲在TransactionInfo對象中進行傳遞同時把信息和當前線程綁定;
    Java代碼 復制代碼 收藏代碼
    1. protected TransactionInfo prepareTransactionInfo(   
    2.         TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {   
    3.   
    4.     TransactionInfo txInfo = new TransactionInfo(txAttr, joinpointIdentification);   
    5.     if (txAttr != null) {   
    6.     .....   
    7.         // 同樣的需要把在getTransaction中得到的TransactionStatus放到TransactionInfo中來。   
    8.         txInfo.newTransactionStatus(status);   
    9.     }   
    10.     else {   
    11.     .......   
    12.    }   
    13.   
    14.     // 綁定事務創建信息到當前線程   
    15.     txInfo.bindToThread();   
    16.     return txInfo;   
    17. }  

    將創建事務的信息返回,然后看到其他的事務管理代碼:
    Java代碼 復制代碼 收藏代碼
    1. protected void commitTransactionAfterReturning(TransactionInfo txInfo) {   
    2.     if (txInfo != null && txInfo.hasTransaction()) {   
    3.         if (logger.isDebugEnabled()) {   
    4.             logger.debug("Invoking commit for transaction on " + txInfo.getJoinpointIdentification());   
    5.         }   
    6.         this.transactionManager.commit(txInfo.getTransactionStatus());   
    7.     }   
    8. }  

    通過transactionManager對事務進行處理,包括異常拋出和正常的提交事務,具體的事務管理器由用戶程序設定。
    Java代碼 復制代碼 收藏代碼
    1. protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {   
    2.     if (txInfo != null && txInfo.hasTransaction()) {   
    3.         if (txInfo.transactionAttribute.rollbackOn(ex)) {   
    4.             ......   
    5.             try {   
    6.                 this.transactionManager.rollback(txInfo.getTransactionStatus());   
    7.             }   
    8.             ..........   
    9.   }   
    10.         else {   
    11.             .........   
    12.             try {   
    13.                 this.transactionManager.commit(txInfo.getTransactionStatus());   
    14.             }   
    15.    ...........   
    16. }   
    17.   
    18. protected void commitTransactionAfterReturning(TransactionInfo txInfo) {   
    19.     if (txInfo != null && txInfo.hasTransaction()) {   
    20.         ......   
    21.         this.transactionManager.commit(txInfo.getTransactionStatus());   
    22.     }   
    23. }  

    Spring通過以上代碼對transactionManager進行事務處理的過程進行了AOP包裝,到這里我們看到為了方便客戶實現聲明式的事務處理,Spring還是做了許多工作的。如果說使用編程式事務處理,過程其實比較清楚,我們可以參考書中的例子:
    Java代碼 復制代碼 收藏代碼
    1. TransactionDefinition td = new DefaultTransactionDefinition();   
    2. TransactionStatus status = transactionManager.getTransaction(td);   
    3. try{   
    4.       ......//這里是我們的業務方法   
    5. }catch (ApplicationException e) {   
    6.    transactionManager.rollback(status);   
    7.    throw e   
    8. }   
    9. transactionManager.commit(status);   
    10.  ........  

    我們看到這里選取了默認的事務配置DefaultTransactionDefinition,同時在創建事物的過程中得到TransactionStatus,然后通過直接調用事務管理器的相關方法就能完成事務處理。
    聲明式事務處理也同樣實現了類似的過程,只是因為采用了聲明的方法,需要增加對屬性的讀取處理,并且需要把整個過程整合到Spring AOP框架中和IoC容器中去的過程。
    下面我們選取一個具體的transactionManager - DataSourceTransactionManager來看看其中事務處理的實現:
    同樣的通過使用AbstractPlatformTransactionManager使用模板方法,這些都體現了對具體平臺相關的事務管理器操作的封裝,比如commit:
    Java代碼 復制代碼 收藏代碼
    1. public final void commit(TransactionStatus status) throws TransactionException {   
    2.     ......   
    3.     DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;   
    4.     if (defStatus.isLocalRollbackOnly()) {   
    5.         ......   
    6.         processRollback(defStatus);   
    7.         return;   
    8.     }   
    9.          .......   
    10.         processRollback(defStatus);   
    11.     ......   
    12.     }   
    13.   
    14.     processCommit(defStatus);   
    15. }  

    通過對TransactionStatus的具體狀態的判斷,來決定具體的事務處理:
    Java代碼 復制代碼 收藏代碼
    1. private void processCommit(DefaultTransactionStatus status) throws TransactionException {   
    2.     try {   
    3.         boolean beforeCompletionInvoked = false;   
    4.         try {   
    5.             triggerBeforeCommit(status);   
    6.             triggerBeforeCompletion(status);   
    7.             beforeCompletionInvoked = true;   
    8.             boolean globalRollbackOnly = false;   
    9.             if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {   
    10.                 globalRollbackOnly = status.isGlobalRollbackOnly();   
    11.             }   
    12.             if (status.hasSavepoint()) {   
    13.             ........   
    14.                status.releaseHeldSavepoint();   
    15.             }   
    16.             else if (status.isNewTransaction()) {   
    17.             ......   
    18.                 doCommit(status);   
    19.             }   
    20.         .........   
    21. }  

    這些模板方法的實現由具體的transactionManager來實現,比如在DataSourceTransactionManager:
    Java代碼 復制代碼 收藏代碼
    1. protected void doCommit(DefaultTransactionStatus status) {   
    2.     //這里得到存在TransactionInfo中已經創建好的事務   
    3.     DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();   
    4.   
    5.     //這里得到和事務綁定的數據庫連接   
    6.     Connection con = txObject.getConnectionHolder().getConnection();   
    7.     ........   
    8.     try {   
    9.     //這里通過數據庫連接來提交事務   
    10.         con.commit();   
    11.     }   
    12.    .......   
    13. }   
    14.   
    15. protected void doRollback(DefaultTransactionStatus status) {   
    16.     DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();   
    17.     Connection con = txObject.getConnectionHolder().getConnection();   
    18.     if (status.isDebug()) {   
    19.         logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");   
    20.     }   
    21.     try {   
    22.     //這里通過數據庫連接來回滾事務   
    23.         con.rollback();   
    24.     }   
    25.     catch (SQLException ex) {   
    26.         throw new TransactionSystemException("Could not roll back JDBC transaction", ex);   
    27.     }   
    28. }  

    我們看到在DataSourceTransactionManager中最后還是交給connection來實現事務的提交和rollback。整個聲明式事務處理是事務處理在Spring AOP中的應用,我們看到了一個很好的使用Spring AOP的例子,在Spring聲明式事務處理的源代碼中我們可以看到:
    1.怎樣封裝各種不同平臺下的事務處理代碼
    2.怎樣讀取屬性值和結合事務處理代碼來完成既定的事務處理策略
    3.怎樣靈活的使用SpringAOP框架。
    如果能夠結合前面的Spring AOP的源代碼來學習,理解可能會更深刻些。

    posted on 2011-10-26 23:40 鴻雁 閱讀(587) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 国产精品成人亚洲| 亚洲熟妇自偷自拍另欧美| 国产V亚洲V天堂A无码| 亚洲精品免费在线| 免费无码午夜福利片| 91av在线免费视频| 四虎精品亚洲一区二区三区| 亚洲国产天堂在线观看| 妇女自拍偷自拍亚洲精品| 最近免费中文字幕大全免费版视频 | 久久久久久99av无码免费网站| 免费v片在线观看品善网| 911精品国产亚洲日本美国韩国 | 99久久国产精品免费一区二区 | 亚洲免费观看视频| 国产免费人视频在线观看免费| 97se亚洲综合在线| 国产福利在线免费| 久久精品国产亚洲av麻豆色欲| 中美日韩在线网免费毛片视频 | 国产男女猛烈无遮挡免费视频网站 | 国产一级一毛免费黄片| 免费午夜爽爽爽WWW视频十八禁| 国产亚洲午夜精品| 国产日产亚洲系列| 人禽伦免费交视频播放| 国产免费私拍一区二区三区| yellow免费网站| 亚洲系列中文字幕| 国产黄色片在线免费观看| 久久久久亚洲国产| 国产va免费精品观看精品| 亚洲精品无码久久久久牙蜜区| 91手机看片国产永久免费| 亚洲自偷自拍另类12p| 无码专区永久免费AV网站| 成年免费a级毛片| 亚洲狠狠狠一区二区三区| 国产成人一区二区三区免费视频| 日韩精品无码免费专区网站| 亚洲日本人成中文字幕|