<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:談?wù)凷pring事務(wù)實(shí)現(xiàn)原理

          共 10790字,需瀏覽 22分鐘

           ·

          2021-10-24 14:12

          你知道的越多,不知道的就越多,業(yè)余的像一棵小草!

          你來,我們一起精進(jìn)!你不來,我和你的競(jìng)爭(zhēng)對(duì)手一起精進(jìn)!

          編輯:業(yè)余草

          cnblogs.com/insaneXs/p/13638034.html

          推薦:https://www.xttblog.com/?p=5281

          前言

          對(duì)于一個(gè)應(yīng)用而言,事務(wù)的使用基本是不可避免的。雖然 Spring 給我們提供了開箱即用的事務(wù)功能 @Transactional,但是,自帶的事務(wù)功能卻也存在控制粒度不夠的缺點(diǎn)。更糟糕的是,@Transactional在某些情況下就失效了。可能一些讀者 baidu/google 一下解決辦法后,失效的問題確實(shí)解決了。但是由于不了解底層的原理,這樣的問題可能在今后的工作中往復(fù)出現(xiàn)。

          Spring事務(wù)

          本文就為大家揭開@Transactional下的秘密。

          原生的事務(wù)管理

          在沒有 Spring 存在的時(shí)候,事務(wù)就已經(jīng)誕生了。其實(shí)框架依賴的還是底層提供的能力,只不過它對(duì)這一過程的抽象和復(fù)用。

          這里我們用底層的 API 來了解下事務(wù)管理的過程( JDBC 為例):

          //?獲取mysql數(shù)據(jù)庫(kù)連接
          Connection?conn?=?DriverManager.getConnection("xxxx");
          conn.setAutoCommit(false);
          statement?=?conn.createStatement();
          //?執(zhí)行sql,返回結(jié)果集
          resultSet?=?statement.executeQuery("xxxx");
          conn.commit();?//提交
          //回滾
          //conn.rollback();

          上面是一個(gè)原生操作事務(wù)的一個(gè)例子,這些過程也是 Spring 事務(wù)逃不開的,只不過在為了編程的效率讓這一過程自動(dòng)化或是透明化的你無(wú)法感知罷了。
          而我們之后做的就是逐步還原這一自動(dòng)化的過程。

          Spring提供的事務(wù)API

          Spring 提供了很多關(guān)于事務(wù)的 API。但是最為基本的就是PlatformTransactionManagerTransactionDefintionTransactionStatus

          事務(wù)管理器 PlatformTransactionManager

          PlatformTransactionManager是事務(wù)管理器的頂層接口。事務(wù)的管理是受限于具體的數(shù)據(jù)源的(例如,JDBC 對(duì)應(yīng)的事務(wù)管理器就是DatasourceTransactionManager),因此PlatformTransactionManager只規(guī)定了事務(wù)的基本操作:創(chuàng)建事務(wù),提交事物和回滾事務(wù)。

          public?interface?PlatformTransactionManager?extends?TransactionManager?{
          ????/**
          ?????*?打開事務(wù)
          ?????*/

          ????TransactionStatus?getTransaction(@Nullable?TransactionDefinition?definition)
          ????????????throws?TransactionException
          ;

          ????/**
          ?????*?提交事務(wù)
          ?????*/

          ????void?commit(TransactionStatus?status)?throws?TransactionException;

          ????/**
          ?????*?回滾事務(wù)
          ?????*/

          ????void?rollback(TransactionStatus?status)?throws?TransactionException;
          }

          同時(shí)為了簡(jiǎn)化事務(wù)管理器的實(shí)現(xiàn),Spring 提供了一個(gè)抽象類AbstractPlatformTransactionManager,規(guī)定了事務(wù)管理器的基本框架,僅將依賴于具體平臺(tái)的特性作為抽象方法留給子類實(shí)現(xiàn)。

          事務(wù)狀態(tài) TransactionStatus

          事務(wù)狀態(tài)是我對(duì)TransactionStatus這個(gè)類的直譯。其實(shí)我覺得這個(gè)類可以直接當(dāng)作事務(wù)的超集來看(包含了事務(wù)對(duì)象,并且存儲(chǔ)了事務(wù)的狀態(tài))。PlatformTransactionManager.getTransaction()時(shí)創(chuàng)建的也正是這個(gè)對(duì)象。
          這個(gè)對(duì)象的方法都和事務(wù)狀態(tài)相關(guān):

          public?interface?TransactionStatus?extends?TransactionExecution,?SavepointManager,?Flushable?{
          ????/**
          ?????*?是否有Savepoint?Savepoint是當(dāng)事務(wù)回滾時(shí)需要恢復(fù)的狀態(tài)
          ?????*/

          ????boolean?hasSavepoint();

          ????/**
          ?????*?flush()操作和底層數(shù)據(jù)源有關(guān),并非強(qiáng)制所有數(shù)據(jù)源都要支持
          ?????*/

          ????@Override
          ????void?flush();

          }

          此外,TransactionStatus還從父接口中繼承了其他方法,都?xì)w總在下方:

          /**
          *?是否是新事務(wù)(或是其他事務(wù)的一部分)
          */

          boolean?isNewTransaction();

          /**
          *?設(shè)置rollback-only?表示之后需要回滾
          */

          void?setRollbackOnly();

          /**
          *?是否rollback-only
          */

          boolean?isRollbackOnly();

          /**
          *?判斷該事務(wù)已經(jīng)完成
          */

          boolean?isCompleted();


          /**
          *?創(chuàng)建一個(gè)Savepoint
          */

          Object?createSavepoint()?throws?TransactionException;

          /**
          *?回滾到指定Savepoint
          */

          void?rollbackToSavepoint(Object?savepoint)?throws?TransactionException;

          /**
          *?釋放Savepoint?當(dāng)事務(wù)完成后,事務(wù)管理器基本上自動(dòng)釋放該事務(wù)所有的savepoint
          */

          void?releaseSavepoint(Object?savepoint)?throws?TransactionException;

          事務(wù)屬性的定義 TransactionDefinition

          TransactionDefinition表示一個(gè)事務(wù)的定義,將根據(jù)它規(guī)定的特性去開啟事務(wù)。

          事務(wù)的傳播等級(jí)和隔離級(jí)別的常量同樣定義在這個(gè)接口中。

          /**
          ?*?返回事務(wù)的傳播級(jí)別
          ?*/

          default?int?getPropagationBehavior()?{
          ?????return?PROPAGATION_REQUIRED;
          }

          /**
          ?*?返回事務(wù)的隔離級(jí)別
          ?*/

          default?int?getIsolationLevel()?{
          ?????return?ISOLATION_DEFAULT;
          }

          /**
          ?*?事務(wù)超時(shí)時(shí)間
          ?*/

          default?int?getTimeout()?{
          ?????return?TIMEOUT_DEFAULT;
          }

          /**
          ?*?是否為只讀事務(wù)(只讀事務(wù)在處理上能有一些優(yōu)化)
          ?*/

          default?boolean?isReadOnly()?{
          ?????return?false;
          }

          /**
          ?*?返回事務(wù)的名稱
          ?*/

          @Nullable
          default?String?getName()?{
          ?????return?null;
          }

          /**
          ?*?默認(rèn)的事務(wù)配置
          ?*/

          static?TransactionDefinition?withDefaults()?{
          ?????return?StaticTransactionDefinition.INSTANCE;
          }

          編程式使用Spring事務(wù)

          有了上述這些 API,就已經(jīng)可以通過編程的方式實(shí)現(xiàn) Spring 的事務(wù)控制了。
          但是 Spring 官方建議不要直接使用PlatformTransactionManager這一偏低層的 API 來編程,而是使用TransactionTemplateTransactionCallback這兩個(gè)偏向用戶層的接口。
          示例代碼如下:

          //設(shè)置事務(wù)的各種屬性;可以猜測(cè)TransactionTemplate應(yīng)該是實(shí)現(xiàn)了TransactionDefinition
          transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
          transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
          transactionTemplate.setTimeout(30000);

          //執(zhí)行事務(wù)?將業(yè)務(wù)邏輯封裝在TransactionCallback中
          transactionTemplate.execute(new?TransactionCallback()?{
          ????@Override
          ????public?Object?doInTransaction(TransactionStatus?transactionStatus)?{
          ????????????//....???業(yè)務(wù)代碼
          ????}
          });

          以上就是 Spring 事務(wù)最基本的原理。但是為什么這些過程對(duì)我們似乎都不可見呢?那是因?yàn)檫@些過程都「通過AOP的方式被織入」了我們的業(yè)務(wù)邏輯中。
          所以,像要深入了解 Spring 事務(wù)原理,還需要了解 AOP 的原理。

          AOP的原理

          AOP 的實(shí)現(xiàn)機(jī)制有兩種:Proxy-based 和 Weaving-based。

          前者是依賴動(dòng)態(tài)代理的方式達(dá)到對(duì)代理類增強(qiáng)的目的。后者應(yīng)該是通過字節(jié)碼增強(qiáng)的方式達(dá)到增強(qiáng)的目的。

          在 Spring 中,一般默認(rèn)使用前者。之后也僅是針對(duì)前者進(jìn)行分析。

          而 Spring 聲明 AOP 的方式也有兩種,一種是通過聲明 Aspect,另一種是通過聲明 Advisor。

          無(wú)論是哪種方式,都需要表達(dá)清楚你要進(jìn)行增強(qiáng)的邏輯 (what)和你要增強(qiáng)的地方(where)。即,需要告訴 Spring 你要增強(qiáng)什么邏輯,并且對(duì)哪些 Bean/哪些方法增強(qiáng)。

          這里的 what 和 where 換成 AOP 中的概念分別就是對(duì)應(yīng)AdvicePointcut

          因?yàn)槭聞?wù)是通過 Advisor 聲明 AOP 的,因此本文也只針對(duì) Advisor 的實(shí)現(xiàn)展開分析。

          動(dòng)態(tài)代理

          既然是動(dòng)態(tài)代理,那么必然存在被代理類(Target),代理類(Proxy),以及類被代理的過程(因?yàn)閷?duì)用戶而言,并不知道類被代理了)。

          被代理的類

          被代理類是最容易知道的,就是那些被 Advisor 的 Pointcut 匹配(classFliter 匹配或是 methodMatches)到的類。

          代理的類

          而代理類是在運(yùn)行時(shí)直接創(chuàng)建的。通常有兩種方式:

          • JDK 的動(dòng)態(tài)代理
          • CGLIB 的動(dòng)態(tài)代理

          二者的區(qū)別是 JDK 動(dòng)態(tài)代理是通過實(shí)現(xiàn)接口的方式(代理的對(duì)象為接口),因此只能代理接口中的方法。

          而 CGLIB 動(dòng)態(tài)代理是通過繼承的方式,因此可以對(duì)對(duì)象中的方法進(jìn)行代理,但是由于是繼承關(guān)系,無(wú)法代理 final 的類和方法(無(wú)法繼承),或是 private 的方法(對(duì)子類不可見)。

          創(chuàng)建代理及取代目標(biāo)類的過程

          創(chuàng)建代理及取代目標(biāo)類主要是應(yīng)用了 Spring 容器在獲取 Bean 時(shí)留下的一個(gè)拓展點(diǎn)。

          Spring 在getBean的時(shí)候,如果 Bean 還不存在會(huì)分三步去創(chuàng)建 Bean:

          • 實(shí)例化
          • 填充屬性
          • 初始化

          實(shí)例化通常是通過反射創(chuàng)建 Bean 對(duì)象的實(shí)例,此時(shí)得到的 Bean 還只是一個(gè)空白對(duì)象。

          填充屬性主要是為這個(gè) Bean 注入其他的 Bean,實(shí)現(xiàn)自動(dòng)裝配。
          而初始化則是讓用戶可以控制 Bean 的創(chuàng)建過程。

          為 Bean 創(chuàng)建代理,并取代原有的 Bean 就是發(fā)生在初始化這一步,更具體的是在BeanPostProcessor.postProcessorAfterInitialization()中。

          ?

          動(dòng)態(tài)代理也有可能在實(shí)例化之前直接創(chuàng)建代理,這種情況發(fā)生在InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()中,此時(shí)的實(shí)例化過程不再是我們上文介紹的通過簡(jiǎn)單反射創(chuàng)建對(duì)象。

          ?

          在眾多的BeanPostProcessor中有一類后置處理器就是專門用于創(chuàng)建代理的。例如,我們要介紹的AbstractAdvisorAutoProxyCreator
          看一下AbstractAutoProxyCreator創(chuàng)建代理的流程:

          1. 先確認(rèn)是否已經(jīng)創(chuàng)建過代理對(duì)象(earlyProxyReferences,避免對(duì)代理對(duì)象在進(jìn)行代理)
          2. 如果沒有,則考慮是否需要進(jìn)行代理(通過wrapIfNecessary)
          3. 如果是特殊的Bean 或者之前判斷過不用創(chuàng)建代理的Bean則不創(chuàng)建代理
          4. 否則看是否有匹配的Advise(匹配方式就是上文介紹的通過PointCut或者IntroducationAdvisor可以直接匹配類)
          5. 如果找到了Advisor,說明需要?jiǎng)?chuàng)建代理,進(jìn)入createProxy
          6. 首先會(huì)創(chuàng)建ProxyFactory,這個(gè)工廠是用來創(chuàng)建AopProxy的,而AopProxy才是用來創(chuàng)建代理對(duì)象的。因?yàn)榈讓哟矸绞接袃煞N(JDK動(dòng)態(tài)代理和CGLIB,對(duì)應(yīng)到AopProxy的實(shí)現(xiàn)就是JdkDynamicAopProxyObjenesisCglibAopProxy),所以這里使用了一個(gè)簡(jiǎn)單工廠的設(shè)計(jì)。ProxyFactory會(huì)設(shè)置此次代理的屬性,然后根據(jù)這些屬性選擇合適的代理方式,創(chuàng)建代理對(duì)象。
          7. 創(chuàng)建的對(duì)象會(huì)替換掉被代理對(duì)象(Target),被保存在BeanFactory.singletonObjects,因此當(dāng)有其他Bean希望注入Target時(shí),其實(shí)已經(jīng)被注入了Proxy。

          以上就是 Spring 實(shí)現(xiàn)動(dòng)態(tài)代理的過程。

          Spring注解式事務(wù)

          我們從編程式事務(wù)了解了 Spring 事務(wù) API 的基本使用方式,又了解了 Spring Advisor 的原理。現(xiàn)在,我們?cè)诨氐?Spring 注解式事務(wù)中,驗(yàn)證下注解式事務(wù)是否就是通過以上這些方式隱藏了具體的事務(wù)控制邏輯。

          從@EnableTransactionManagement說起

          @EnableTransactionManagement是開啟注解式事務(wù)的事務(wù)。如果注解式事務(wù)真的有玄機(jī),那么@EnableTransactionManagement就是我們揭開秘密的突破口。

          @Target(ElementType.TYPE)
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          @Import(TransactionManagementConfigurationSelector.class)
          public?@interface?EnableTransactionManagement?
          {

          ????/**
          ?????*?用來表示默認(rèn)使用JDK?Dynamic?Proxy還是CGLIB?Proxy
          ?????*/

          ????boolean?proxyTargetClass()?default?false;

          ????/**
          ?????*?表示以Proxy-based方式實(shí)現(xiàn)AOP還是以Weaving-based方式實(shí)現(xiàn)AOP
          ?????*/

          ????AdviceMode?mode()?default?AdviceMode.PROXY;

          ????/**
          ?????*?順序
          ?????*/

          ????int?order()?default?Ordered.LOWEST_PRECEDENCE;

          }

          @EnableTransactionManagement注解看起來并沒有特別之處,都是一些屬性的配置。但它卻通過@Import引入了另一個(gè)配置TransactionManagentConfigurationSelector

          TransactionManangementConfigurationSelector

          在 Spring 中,Selector通常都是用來選擇一些 Bean,向容器注冊(cè)BeanDefinition的(嚴(yán)格意義上 Selector 僅時(shí)選擇過程,注冊(cè)的具體過程是在ConfigurationClasspathPostProcessor解析時(shí),調(diào)用ConfigurationClassParser觸發(fā))。
          主要的邏輯就是根據(jù)代理模式,注冊(cè)不同的 BeanDefinition。
          對(duì) Proxy 的模式而言,注入的有兩個(gè):

          • AutoProxyRegistrar
          • ProxyTransactionManagementConfiguration

          AutoProxyRegistrar

          Registrar 同樣也是用來向容器注冊(cè) Bean 的,在 Proxy 的模式下,它會(huì)調(diào)用AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);向容器中注冊(cè)InfrastructureAdvisorAutoProxyCreator。而這個(gè)類就是我們上文提到的AbstractAdvisorAutoProxyCreator的子類。
          從而,我們完成了我們的第一個(gè)條件——AOP代理。

          ProxyTransactionManagementConfiguration

          ProxyTransactionManagementConfiguration是一個(gè)配置類,如果算上其繼承的父類,一共是聲明了四個(gè)類:

          1. TransactionalEventListenerFactory
          2. BeanFactoryTransactionAttributeSourceAdvisor
          3. TransactionAttributeSource
          4. TransactionInterceptor

          后三個(gè)類相對(duì)比較重要,我們一一分析。

          BeanFactoryTransactionAttributeSourceAdvisor

          從名字看就知道這是一個(gè) Advisor,那么它身上應(yīng)該有 Pointcut 和 Advise。
          其中的 Pointcut 是TransactionAttributeSourcePointcut,主要是一些 filter 和 matches 之類的方法,用來匹配被代理類。
          而 Adivise 就是我們之后要介紹的TransactionInterceptor

          TransactionAttributeSource

          TransactionAttributeSource只是一個(gè)接口,擴(kuò)展了TransactionDefinition,增加了isCandidateClass()的方法(可以用來幫助 Pointcut 匹配)。
          這里使用的具體實(shí)現(xiàn)是AnnotationTransactionAttributeSource。因?yàn)樽⒔馐绞聞?wù)候選類(即要被代理的類)是通過@Transactional注解標(biāo)識(shí)的,并且所有的事務(wù)屬性也都來自@Transactional注解。

          TransactionInterceptor

          剛才我們說了,TransactionInterceptor就是我們找的Advise。
          這個(gè)類稍微復(fù)雜一點(diǎn),首先根據(jù)事務(wù)處理相關(guān)的邏輯都放在了其父類TransactionAspectSupport中。此外,為了適配動(dòng)態(tài)代理的反射調(diào)用(兩種代理方式),實(shí)現(xiàn)了MethodInterceptor接口。
          也就是說,反射發(fā)起的入口是MethodInterceptor.invoke(),而反射邏輯在TransactionAspectSupport.invokeWithinTransaction()中。
          我們可以簡(jiǎn)單看invokeWithTransaction()方法中的部分代碼:

          @Nullable
          protected?Object?invokeWithinTransaction(Method?method,?@Nullable?Class?targetClass,
          ????????final?InvocationCallback?invocation)
          ?throws?Throwable?
          {

          ????
          ????TransactionAttributeSource?tas?=?getTransactionAttributeSource();
          ????final?TransactionAttribute?txAttr?=?(tas?!=?null???tas.getTransactionAttribute(method,?targetClass)?:?null);
          ????final?TransactionManager?tm?=?determineTransactionManager(txAttr);

          ????//省略部分代碼
          ????
          ????//獲取事物管理器
          ????PlatformTransactionManager?ptm?=?asPlatformTransactionManager(tm);
          ????final?String?joinpointIdentification?=?methodIdentification(method,?targetClass,?txAttr);

          ????if?(txAttr?==?null?||?!(ptm?instanceof?CallbackPreferringPlatformTransactionManager))?{
          ????????//?打開事務(wù)(內(nèi)部就是getTransactionStatus的過程)
          ????????TransactionInfo?txInfo?=?createTransactionIfNecessary(ptm,?txAttr,?joinpointIdentification);

          ????????Object?retVal;
          ????????try?{
          ????????????//?執(zhí)行業(yè)務(wù)邏輯?invocation.proceedWithInvocation();
          ????????}
          ????????catch?(Throwable?ex)?{
          ????????????//?異常回滾
          ????????????completeTransactionAfterThrowing(txInfo,?ex);
          ????????????throw?ex;
          ????????}
          ????????finally?{
          ????????????cleanupTransactionInfo(txInfo);
          ????????}

          ????????//省略部分代碼
          ????????
          ????????//提交事物
          ????????commitTransactionAfterReturning(txInfo);
          ????????return?retVal;
          ????}
          }

          雖然代碼比我們之前的復(fù)雜,但是其主體結(jié)構(gòu)依然是我們編程式事務(wù)的常見那幾步。

          行文至此,隱藏在 Spring 自動(dòng)事務(wù)下的邏輯都分析的差不多了。未避免枯燥,本文并沒有對(duì)代碼一行行的分析,而是希望能夠幫助讀者把握大概的原理。

          事務(wù)失效的常見情況及其背后的原因

          數(shù)據(jù)庫(kù)存儲(chǔ)引擎不支持

          常見的像 mySQL 的 myISAM 存儲(chǔ)引擎就不支持事務(wù)功能。
          這很好理解,說到底事務(wù)是數(shù)據(jù)庫(kù)的功能,如果數(shù)據(jù)庫(kù)本身就沒有這個(gè)功能,那上層再怎么五花八門也是沒用的。

          未指定RollbackOn,且拋出的異常并非RuntimeException

          這個(gè)背后的原因我們可以從DefualtTransactionAttribute中來找。

          //可見默認(rèn)觸發(fā)回滾的異常是RuntimeException和Error
          @Override
          public?boolean?rollbackOn(Throwable?ex)?{
          ????return?(ex?instanceof?RuntimeException?||?ex?instanceof?Error);
          }

          因此阿里巴巴代碼規(guī)范倡議是顯示指定 rollbackOn 為 Exception

          同一個(gè)類中調(diào)用事務(wù)方法

          這是在 Proxy 模式下才會(huì)失效的。
          根據(jù)上文我們了解了 Spring 事務(wù)是機(jī)遇動(dòng)態(tài)代理的,而當(dāng)在類當(dāng)中調(diào)用事務(wù)的方法時(shí),動(dòng)態(tài)代理是無(wú)法生效的,因?yàn)榇藭r(shí)你拿到的 this 指向的已經(jīng)是被代理類(Target),而非代理類(Proxy)。

          非公開方法上的事務(wù)

          如果你將@Transactional注解應(yīng)用在一個(gè) non-public 的方法上(即便是 protected 和 defualt 的方法),你會(huì)發(fā)現(xiàn)事務(wù)同樣不生效(也是在 Proxy 模式下)。

          有讀者可能會(huì)疑問,GCLIB 的局限應(yīng)該是在 private 或是 final 的方法上,private 方法代理失效還能理解,為什么 protected 和 defualt 方法也不行呢?

          其實(shí),non-public 方法失效的真正原因不是動(dòng)態(tài)代理的限制,而是 Spring 有意為之。

          之前我們介紹了TransactionAttributeSource會(huì)幫助 Pointcut 匹配類和方法,而在AnnotationTransactionAttributeSource中,有一個(gè)屬性final boolean publicMethodsOnly表示是否只允許公有方法。這個(gè)屬性在默認(rèn)的構(gòu)造函數(shù)中被設(shè)置了 true。因此代理只會(huì)對(duì) public 方法生效。

          網(wǎng)上找了下 Spring 這么設(shè)計(jì)的目的,有說業(yè)務(wù)類就是應(yīng)該基于接口方法調(diào)用的,因此總為 public。也有說這是為了讓 CGLIB 和 JDK dynamic Proxy 保持一致。

          Emm... 我覺得 Duck 不必。

          不過 Spring 也沒有把著屬性限制死,如果你真想在 non-public 的方法上使用自動(dòng)事務(wù),使點(diǎn)手段修改這個(gè)變量即可(例如搞個(gè)高優(yōu)先級(jí)的BeanPostProcessor,在通過反射修改這個(gè)變量)。但是盡量還是按照規(guī)范來吧。

          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    国产精品人妻在线 | 欧美在线看片 | 国产精品 一道在线 | 亚洲精品久久久久 | 色老板综合 |