<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

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

    共 10790字,需瀏覽 22分鐘

     ·

    2021-10-24 14:12

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

    你來,我們一起精進(jìn)!你不來,我和你的競爭對(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在某些情況下就失效了??赡芤恍┳x者 baidu/google 一下解決辦法后,失效的問題確實(shí)解決了。但是由于不了解底層的原理,這樣的問題可能在今后的工作中往復(fù)出現(xiàn)。

    Spring事務(wù)

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

    原生的事務(wù)管理

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

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

    //?獲取mysql數(shù)據(jù)庫連接
    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)化或是透明化的你無法感知罷了。
    而我們之后做的就是逐步還原這一自動(dòng)化的過程。

    Spring提供的事務(wù)API

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

    事務(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í)為了簡化事務(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。

    無論是哪種方式,都需要表達(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)系,無法代理 final 的類和方法(無法繼承),或是 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í)例化過程不再是我們上文介紹的通過簡單反射創(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è)簡單工廠的設(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 的原理?,F(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()中。
    我們可以簡單看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)?{
    ????????????//?異?;貪L
    ????????????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ù)庫存儲(chǔ)引擎不支持

    常見的像 mySQL 的 myISAM 存儲(chǔ)引擎就不支持事務(wù)功能。
    這很好理解,說到底事務(wù)是數(shù)據(jù)庫的功能,如果數(shù)據(jù)庫本身就沒有這個(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)代理是無法生效的,因?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="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

        • <dd id="5sdj3"></dd>
          <dfn id="5sdj3"></dfn>
        • <th id="5sdj3"></th>
          <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

          • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
          • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
            青娱乐大香蕉 | 大雞巴疯狂浓精合集 | 亚洲日本淫色无码视频 | 国产精品综合久久久 | 五月丁香激情四射 |