精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

可以,很強,68行代碼實現Bean的異步初始化,粘過去就能用

開發 架構
SOFABoot 是螞蟻金服開源的基于 Spring Boot 的研發框架,它在 Spring Boot 的基礎上,提供了諸如 Readiness Check,類隔離,日志空間隔離等能力。

你好呀,我是歪歪。

前兩天在看 SOFABoot 的時候,看到一個讓我眼前一亮的東西,來給大家盤一下。

SOFABoot,你可能不眼熟,但是沒關系,本文也不是給你講這個東西的,你就認為它是 SpringBoot 的變種就行了。

因為有螞蟻金服背書,所以主要是一些金融類的公司在使用這個框架:

圖片

官方介紹是這樣的:

SOFABoot 是螞蟻金服開源的基于 Spring Boot 的研發框架,它在 Spring Boot 的基礎上,提供了諸如 Readiness Check,類隔離,日志空間隔離等能力。在增強了 Spring Boot 的同時,SOFABoot 提供了讓用戶可以在 Spring Boot 中非常方便地使用 SOFA 中間件的能力。

上面這些功能都很強大,但是我主要是分享一下它的這個小功能:https://help.aliyun.com/document_detail/133162.html

圖片

這個功能可以讓 Bean 的初始化方法在異步線程里面執行,從而加快 Spring 上下文加載過程,提高應用啟動速度。

為什么看到功能的時候,我眼前一亮呢,因為我很久之前寫過這篇文章《我是真沒想到,這個面試題居然從11年前就開始討論了,而官方今年才表態。》

里面提到的面試題是這樣的:

Spring 在啟動期間會做類掃描,以單例模式放入 ioc。但是 spring 只是一個個類進行處理,如果為了加速,我們取消 spring 自帶的類掃描功能,用寫代碼的多線程方式并行進行處理,這種方案可行嗎?為什么?

當時通過 issue 找到了官方對于這個問題回復總結起來就是:應該是先找到啟動慢的根本原因,而不是把問題甩鍋給 Spring。這部分對于 Spring 來說,能不動,就別動。

僅從“啟動加速-異步初始化方法”這個標題上來看,Spring 官方不支持的東西 SOFABoot 支持了。所以這玩意讓我眼前一亮,我倒要看看你是怎么搞得。

先說結論:SOFABoot 的方案能從一定程度上解決問題,但是它依賴于我們編碼的時候指定哪些 Bean 是可以異步初始化的,這樣帶來的好處是不必考慮循環依賴、依賴注入等等各種復雜的情況了,壞處就是需要程序員自己去識別哪些類是可以異步初始化的。

我倒是覺得,程序員本來就應該具備“識別自己的項目中哪些類是可以異步初始化”的能力。

但是,一旦要求程序員來主動去識別了,就已經“輸了”,已經不夠驚艷了,在實現難度上就不是一個級別的事情了。人家 Spring 想的可是框架給你全部搞定,頂多給你留一個開關,你開箱即用,啥都不用管。

但是總的來說,作為一次思路演變為源碼的學習案例來說,還是很不錯的。

我們主要是看實現方案和具體邏輯代碼,以 SOFABoot 為抓手,針對其“異步初始化方法”聚焦下鉆,把源碼當做紐帶,協同 Spring,打出一套“我看到了->我會用了->我拿過來->我看懂了->是我的了->寫進簡歷”的組合拳。

Demo

先搞個 Demo 出來,演示一波效果,先讓你直觀的看到這是個啥玩意。

這個 Demo 非常之簡單,幾行代碼就搞定。

先搞兩個 java 類,里面有一個 init 方法:

圖片圖片

然后把他們作為 Bean 交給 Spring 管理,Demo 就搭建好了:

圖片圖片

直接啟動項目,啟動時間只需要 1.152s,非常絲滑:

圖片圖片

然后,注意,我要稍微的變一下形。

在注入 Bean 的時候觸發一下初始化方法,模擬實際項目中在 Bean 的初始化階段,既在 Spring 項目啟動過程中,做一些數據準備、配置拉取等相關操作:

圖片圖片

再次重啟一下項目,因為需要執行兩個 Bean 的初始化動作,各需要 5s 時間,而且是串行執行,所以啟動時間直接來到了 11.188s:

圖片圖片

那么接下來,就是見證奇跡的時刻了。

我加上 @SofaAsyncInit 這樣的一個注解:

圖片圖片

你先別管這個注解是哪里來的,從這個注解的名稱你也知道它是干啥的:異步執行初始化。

這個時候我再啟動項目:

圖片圖片

從日志中可以看到:

  1. whyBean 和 maxBean 的 init 方法是由兩個不同的線程并行執行的。
  2. 啟動時間縮短到了 6.049s。

所以 @SofaAsyncInit 這個注解實現了“指定 Bean 的初始化方法實現異步化”。

你想想,如果你有 10 個 Bean,每個 Bean 都需要 1s 的時間做初始化,總計 10s。

但是這些 Bean 之間其實不需要串行初始化,那么用這個注解,并行只需要 1s,搞定。

到這里,你算是看到了這樣的東西存在,屬于“我看到了”。

接下來,我們進入到“我會用了”這個環節。

怎么來的。

在解讀原理之前,我還得告訴你這個注解到底是怎么來的。

它屬于 SOFABoot 框架里面的注解,首先你得把你的 SpringBoot 修改為 SOFABoot。

這一步參照官方文檔中的“快速開始”部分,非常的簡單:https://www.sofastack.tech/projects/sofa-boot/quick-start/

第一步就是把項目中 pom.xml 中的:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>${spring.boot.version}</version>
    <relativePath/> 
</parent>

替換為:

<parent>
    <groupId>com.alipay.sofa</groupId>
    <artifactId>sofaboot-dependencies</artifactId>
    <version>${sofa.boot.version}</version>
</parent>

這里的 ${sofa.boot.version} 指定具體的 SOFABoot 版本,我這里使用的是最新的 3.18.0 版本。

然后我們要使用 @SofaAsyncInit 注解,所以需要引入以下 maven:

<dependency>
    <groupId>com.alipay.sofa</groupId>
    <artifactId>runtime-sofa-boot-starter</artifactId>
</dependency>

對于 pom.xml 文件的變化,就只有這么一點:

圖片圖片

最后,在工程的 application.properties 文件下添加 SOFABoot 工程一個必須的參數配置,spring.application.name,用于標示當前應用的名稱。

# Application Name
spring.application.name=SOFABoot Demo

就搞定了,我就完成了一個從 SpringBoot 切換為 SOFABoot 這個大動作。

當然了,我這個是一個 Demo 項目,結構和 pom 依賴都非常簡單,所以切換起來也非常容易。如果你的項目比較大的話,可能會遇到一些兼容性的問題。

但是,注意我要說但是了。

你是在學習摸索階段,Demo 一定要簡單,越小越好,越純凈越好。所以這個切換的動作對你搭建的一個全新的 Demo 項目來說沒啥難度,不會遇到任何問題。

這個時候,你就可以使用 @SofaAsyncInit 注解了:

圖片圖片

到這里,恭喜你,會用了。

拿來吧你

不知道你看到這里是什么感受。

反正對于我來說,如果僅僅是為了讓我能使用這個注解,達到異步初始化的目的,要讓我從熟悉的 SpringBoot 修改為聽都沒聽過的 SOFABoot,即使這個框架背后有阿里給它背書,我肯定也是不會這么干的。

所以,對于這一類“人有我無”的東西,我都是采取“拿來吧你”策略。

你想,最開始的我就說了,SOFABoot 是 SpringBoot 的變種,它的底層還是 SpringBoot。

而 SOFABoot 又是開源的,整個項目的源碼我都有了:https://github.com/sofastack/sofa-boot/blob/master/README_ZH.md

從其中剝離出一個基于 SpringBoot 做的小功能,融入到我自己的 SpringBoot 項目中,還玩意難道不是手到擒來的事情?

不過就是稍微高級一點的 cv 罷了。

首先,你得把 SOFABoot 的源碼下載下來,或者在另外的一個項目中引用它,把自己的項目恢復為一個 SpringBoot 項目。

圖片圖片

我這邊是直接把 SOFABoot 源碼搞下來了,先把源碼里面的 @SofaAsyncInit 注解粘到項目里面來,然后從 @SofaAsyncInit 注解入手,發現除了測試類只有一個 AsyncInitBeanFactoryPostProcessor 類在對其進行使用:

圖片圖片

所以把這個類也搬運過來。

搬運過來之后你會發現有一些類找不到導致報錯:

圖片圖片

針對這部分類,你可以采取無腦搬運的方式,也可以稍加思考替換一些。

比如我就分為了兩種類型:

圖片圖片

標號為 ① 的部分,我是直接粘貼到自己的項目中,然后使用項目中的類。

標號為 ② 的部分,比如 BeanLoadCostBeanFactory 和 SofaBootConstants,他們的目的是為了獲取一個 moduleName 變量:

圖片圖片

我也不知道這個 moduleName 是啥,所以我采取的策略是自己指定一個:

圖片圖片

至于 ErrorCode 和 SofaLogger,日志相關的,就用自己項目里面的日志就行了。

就是這個意思:

圖片

這樣處理完成之后,AsyncInitBeanFactoryPostProcessor 類不報錯了,接著看這個類在哪里使用到了。

就這樣順藤摸瓜,最后搬運完成之后,就是這些類移過來了:

圖片

除了這些類之外,你還會把這個 spring.factories 搬運過來,在項目啟動時把這幾個相關的類加載進去:

圖片

然后再次啟動這個和 SOFABoot 沒有一點關系的項目:

圖片

你會發現,你的項目也具備異步初始化 Bean 的功能了。

你要再進一步,把它直接封裝為一個 spring-boot-starter-asyncinitbean,發布到你們公司的私服里面。

其他團隊也能開箱即用的使用這個功能了。

別問,問就是你自己獨立開發出來的,掌握全部源碼,技術風險可控:

啃原理

在開始啃原理之前,我先多比比兩句。

我寫文章的時候,為什么要把“拿來吧你”這一小節放在“啃原理”之前,我是有考慮的。

當我們把“異步初始化”這個功能點剝離出來之后,你會發現,要實現這個功能,一共也沒涉及到幾個類。

聚焦點從一整個項目變成了幾個類而已,至少從感官上不會覺得那么的難,對閱讀其源碼產生太大的抗拒心理。

而我之前很多關于源碼閱讀的文章,都強調過這一點:帶著疑問去調試源碼,要抓住主干,謹防走偏。

前面這一小節,不過是把這一句話具化了而已。即使沒有把這些類剝離出來,你直接基于 SOFABoot 來調試這個功能。在你搞清楚“異步初始化”這個功能的實現原理之前,理論上你的關注點和注意力不應該被上面這些類之外的任何一個類給吸引走。

接下來,我們就帶你啃一下原理。

關于原理部分,我們的突破口肯定是看 @SofaAsyncInit 這個注解的在哪個地方被解析的。

你仔細看這個注解里面有一個 value 屬性,默認為 true,上面的注解說:用來標注是否應該對 init 方法進行異步調用。

而使用到這個 value 值的地方,就只有下面這一個地方:

com.alipay.sofa.runtime.spring.AsyncInitBeanFactoryPostProcessor#registerAsyncInitBean

判斷為 true 的時候,執行了一個 registerAsyncInitBean 方法。

從方法名稱也知道,它是把可以異步執行的 init 方法的 Bean 收集起來。

所以看源碼可以看出,這里面是用 Map 來進行的存儲,提供了一個 register 和 get 方法:

那么這個 Map 里面到底放的是啥呢?

我也不知道,打個斷點瞅一眼,不就行了:

通過斷點調試,我們知道這個里面把項目中哪些 Bean 可以異步執行 init 方法通過 Map 存放了起來。

那么問題就來了:它怎么知道哪些 Bean 可以異步執行 init 呢?

很簡單啊,因為我在對應的 Bean 上打上了 @SofaAsyncInit 注解。所以可以通過掃描注解的方式找到這些 Bean。

所以你說 AsyncInitBeanFactoryPostProcessor 這個類是在干啥?

肯定核心邏輯就是在解析標注了 @SofaAsyncInit 注解的地方嘛。

到這里,我們通過注解的 value 屬性,找到了 AsyncInitBeanHolder 這個關鍵類。

知道了這個類里面有一個 Map,里面維護的是所有可以異步執行 init 方法的 Bean 和其對應的 init 方法。

好,你思考一下,接下來應該干啥?

接下來肯定是看哪個地方在從這個 Map 里面獲取數據出來,獲取數據的時候,就說明是要異步執行這個 Bean 的 init 方法的時候。

不然它把數據放到 Map 里面干啥?玩嗎?

調用 getAsyncInitMethodName 方法的地方,也在 AsyncProxyBeanPostProcessor 類里面:

com.alipay.sofa.runtime.spring.AsyncProxyBeanPostProcessor#postProcessBeforeInitialization

AsyncProxyBeanPostProcessor 類實現了 BeanPostProcessor 接口,并重新了其 postProcessBeforeInitialization 方法。

在這個 postProcessBeforeInitialization 方法里面,執行了從 Map 里面拿對象的動作。

如果獲取到了則通過 AOP 編程,編織進一個 AsyncInitializeBeanMethodInvoker 方法。

把 bean, beanName, methodName 都傳遞了進去:

所以關鍵點,就在 AsyncInitializeBeanMethodInvoker 里面,因為這個里面有真正判斷是否要進行異步初始化的邏輯,主要解讀一下這個類。

首先,關注一下它的這三個參數:

  • initCountDownLatch:是 CountDownLatch 對象,其中 count 初始化為 1
  • isAsyncCalling:表示是否正在異步執行 init 方法。
  • isAsyncCalled:表示是否已經異步執行過 init 方法。

通過這三個字段,就可以感知到一個 Bean 是否已經或者正在異步執行其 init 方法。

這個類的核心邏輯就是把可以異步執行、但是還沒有執行 init 方法的 bean ,把它的 init 方法扔到線程池里面去執行:

看一下在上面的 invoke 方法中的 if 方法:

if (!isAsyncCalled && methodName.equals(asyncMethodName))

isAsyncCalled,首先判斷是否已經異步執行過這個 bean 的 init 方法了。

然后看看 methodName.equals(asyncMethodName),要反射調用的方法是否是之前在 map 中維護的 init 方法。

如果都滿足,就扔到線程池里面去執行,這樣就算是完成了異步 init。

如果不滿足呢?

首先,你想想不滿足的時候說明什么情況?

是不是說明一個 Bean 的 init 方法在項目啟動過程中不只被調用一次。

就像是這樣:

雖然,我不知道為什么一個 Bean 要執行兩次 init 方法,大概率是代碼寫的有問題。

但是我不說,我也不給你拋出異常,我反正就是給你兼容了。

所以,這段代碼就是在處理這個情況:

如果發現有多次調用,那么只要第一次異步初始化完成了,即 isAsyncCalling 為 false ,你可以繼續執行反射調用初始化方法的動作。

這個 invoke 方法的邏輯就是這樣,主要是有一個線程池在里面。

那么這個線程池是哪里來的呢?

com.alipay.sofa.runtime.spring.async.AsyncTaskExecutor

在第一次 submit 任務的時候,框架會幫我們初始化一個線程池出來。

然后通過這個線程池幫我們完成異步初始化的目標。

所以你想想,整個過程是非常清晰的。首先找出來哪些 Bean 上標注了 @SofaAsyncInit 注解,找個 Map 維護起來,接著搞個 AOP 切面,看看哪些 Bean 能在 Map 里面找到,在線程池里面通過動態代理,調用其 init 方法。

就完了。

對不對?

好,那么問題就來了?

為什么我不直接在 init 方法里面搞個線程池呢,就像是這樣。

先注入一個自定義線程池,同時注釋掉 @SofaAsyncInit 注解:

在指定 Bean 的 init 方法中使用該線程池:

這也不也是能達到“異步初始化”的目的嗎?

你說對不對?

不對啊,對個錘子對。

你看啟動日志:

服務已經啟動完成了,但是 4s 之后,Bean 的 init 方法才執行完畢。

在這期間,如果有請求要使用對應的 Bean 怎么辦?

拿著一個還未執行完成 init 方法的 Bean 框框一頓用,這畫面想想就很美。

所以怎么辦?

我也不知道,看一下 SOFABoot 里面是怎么解決這個問題的。

在我們前面提到的線程池里面,有這樣的一個方法:

com.example.asyncthreadpool.spring.AsyncTaskExecutor#ensureAsyncTasksFinish

在這個方法里面,調用了 future 的 get 方法進行阻塞等待。當所有的 future 執行完成之后,會關閉線程池。

這個 FUTURES 是什么玩意,怎么來的?

它就是執行 submitTask 方法時,維護進行去的,里面裝的就是一個個異步執行的 init 方法:

所以它通過這個方法可以確保能感知到所有的通過這個線程池執行的 init 方法都執行完畢。

現在,方法有了,你先思考一下,我們什么時候觸發這個方法的調用呢?

是不是應該在 Spring 容器告訴你:小老弟,我這邊所有的 Bean 都搞定了,你這邊啥情況了?

這個時候你就需要調用一下這個方法。

而 Spring 容器加載完成之后,會發布這樣的一個事件。也就是它:

所以,SOFABoot 的做法就是監聽這個事件:

com.example.asyncthreadpool.spring.AsyncTaskExecutionListener

這樣,即可確保在異步線程中執行的 init 方法的 Bean 執行完成之后,容器才算啟動成功,對外提供服務。

到這里,原理部分我算是講完了。

但是寫到這里的時候,我突然冒出了一個寫之前沒有過的想法:在整個實現的過程中,最關鍵的有兩個東西:

  1. 一個 Map:里面維護的是所有可以異步執行 init 方法的 Bean 和其對應的 init 方法。
  2. 一個線程池:異步執行 init 方法。

而這個 Map 是怎么來的?

不是通過掃描 @SofaAsyncInit 注解得到的嗎?

那么掃描出來的 @SofaAsyncInit 怎么來的?

不就是我寫代碼的時候主動標注上去的嗎?

所以,我們是不是可以完全不用 Map ,直接使用異步線程池:

剩去中間環節,直接一步到位,只需要留下兩個類即可:

我這里把這個兩個類貼出來。

AsyncTaskExecutionListener:

public class AsyncTaskExecutionListener implements PriorityOrdered,
                                       ApplicationListener<ContextRefreshedEvent>,
                                       ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (applicationContext.equals(event.getApplicationContext())) {
            AsyncTaskExecutor.ensureAsyncTasksFinish();
        }
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 1;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

AsyncTaskExecutor:

@Slf4j
public class AsyncTaskExecutor {
    protected static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    protected static final AtomicReference<ThreadPoolExecutor> THREAD_POOL_REF = new AtomicReference<ThreadPoolExecutor>();

    protected static final List<Future> FUTURES = new ArrayList<>();

    public static Future submitTask(Runnable runnable) {
        if (THREAD_POOL_REF.get() == null) {
            ThreadPoolExecutor threadPoolExecutor = createThreadPoolExecutor();
            boolean success = THREAD_POOL_REF.compareAndSet(null, threadPoolExecutor);
            if (!success) {
                threadPoolExecutor.shutdown();
            }
        }
        Future future = THREAD_POOL_REF.get().submit(runnable);
        FUTURES.add(future);
        return future;
    }

    private static ThreadPoolExecutor createThreadPoolExecutor() {
        int threadPoolCoreSize = CPU_COUNT + 1;
        int threadPoolMaxSize = CPU_COUNT + 1;
        log.info(String.format(
                "create why-async-init-bean thread pool, corePoolSize: %d, maxPoolSize: %d.",
                threadPoolCoreSize, threadPoolMaxSize));
        return new ThreadPoolExecutor(threadPoolCoreSize, threadPoolMaxSize, 30,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
    }

    public static void ensureAsyncTasksFinish() {
        for (Future future : FUTURES) {
            try {
                future.get();
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        }

        FUTURES.clear();
        if (THREAD_POOL_REF.get() != null) {
            THREAD_POOL_REF.get().shutdown();
            THREAD_POOL_REF.set(null);
        }
    }
}

你只需要把這兩個類,一共 68 行代碼,粘到你的項目中,然后把 AsyncTaskExecutionListener 以 @Bean 的方式注入:

@Bean
public AsyncTaskExecutionListener asyncTaskExecutionListener() {
    return new AsyncTaskExecutionListener();
}

恭喜你,你項目中的 Bean 也可以異步執行 init 方法了,使用方法就像這樣式兒的:

但是,如果你要對比這兩種寫的法的話:

圖片圖片

肯定是選注解嘛,優雅的一比。

所以,我現在問你一個問題:清理聊聊異步初始化 Bean 的思路。

然后在追問你一個問題:如果通過自定義注解的方式實現?需要用到 Spring 的那些擴展點?

還思考個毛啊,不就是這個過程嗎?

圖片圖片

回想一下前面的內容,是不是品出點味道了,是不是有點感覺了,是不是覺得自己又行了?

其實說真的,這個方案,當需要人來主動標識哪些 Bean 是可以異步初始化的時候,就已經“輸了”,已經不夠驚艷了。

但是,你想想本文只是想教你“異步初始化”這個點嗎?

不是的,只是以“異步初始化”為抓手,試圖教你一種源碼解讀的方法,找到撕開 Spring 框架的又一個口子,這才是重要的。

最后,前兩天阿里開發者公眾號也發布了一篇叫《Bean異步初始化,讓你的應用啟動飛起來》的文章,想要達成的目的一樣,但是最終的落地方案可以說差距很大。這篇文章沒有具體的源碼,但是也可以對比著看一下,取長補短,融會貫通。

行了,我就帶你走到這了,我只是給你指個路,剩下的路就要你自己走了。

天黑路滑,燈火昏暗,抓住主干,及時回頭。

好了,本文的技術部分就到這里啦。

責任編輯:武曉燕 來源: why技術
相關推薦

2011-03-16 10:52:20

2021-06-26 16:14:11

虛擬機注冊鉤子

2024-10-29 11:27:27

2021-06-21 09:37:05

代碼開源可視化

2024-07-31 11:26:05

反射BeanXML

2010-08-20 16:02:45

Cassandra集群

2011-08-16 14:54:12

iphone開發APP

2023-11-12 23:08:17

C++初始化

2009-08-31 10:38:34

C#變量初始化

2025-04-25 11:25:00

SpringBean初始化

2010-01-05 15:35:21

.NET Framew

2010-02-01 14:21:24

C++初始化列表

2012-03-13 13:38:42

Java

2009-06-10 16:17:00

Netbeans JT初始化

2021-07-07 05:00:17

初始化源碼

2020-02-25 11:15:46

代碼開發AI

2010-01-22 15:47:37

VB.NET初始化網格

2019-11-04 13:50:36

Java數組編程語言

2009-09-08 09:48:34

LINQ初始化數組

2009-11-11 15:29:15

ADO初始化
點贊
收藏

51CTO技術棧公眾號

亚洲成人av一区二区| 盗摄精品av一区二区三区| 中国日韩欧美久久久久久久久| 天天影视综合色| 国产一级免费在线观看| 久久精品国产99久久6| 久久99精品国产99久久6尤物| 久久久午夜精品福利内容| 亚洲成人不卡| 一区二区三区色| 日本不卡一区二区三区在线观看| 国产又粗又黄又爽| 一区二区国产在线观看| 视频在线观看99| www.四虎在线| 色综合视频一区二区三区日韩| 夜夜嗨av一区二区三区| 日本一区二区视频| 色综合久久久久久| 国产一区二区三区精品欧美日韩一区二区三区| 国模叶桐国产精品一区| 国产白丝一区二区三区| 欧美交a欧美精品喷水| 69久久夜色精品国产69蝌蚪网| 日韩欧美一区二| 日本电影在线观看网站| 久久久久久久精| 电影午夜精品一区二区三区 | 黑丝一区二区| 日韩视频一区在线| 日本免费www| 欧美变态网站| 日韩欧美成人一区二区| 日本人视频jizz页码69| 成人免费网站视频| 偷拍一区二区三区四区| 青青草视频国产| 日本免费视频在线观看| 国产欧美精品一区| 久久久久久久久久久久久9999| 国产夫妻在线观看| 国产真实精品久久二三区| 国产黑人绿帽在线第一区| 自拍偷拍欧美亚洲| 在线日本高清免费不卡| 久久99精品久久久久久青青91| 青青青视频在线播放| 国产成人福利av| 日韩精品专区在线| 熟妇无码乱子成人精品| 精品一区二区三区中文字幕在线 | 999热精品视频| 国产美女久久| 欧美三级日本三级少妇99| 欧美牲交a欧美牲交aⅴ免费真| 国产h片在线观看| 亚洲一二三区视频在线观看| 人人妻人人澡人人爽欧美一区| 国产三区视频在线观看| 亚洲免费观看高清完整版在线观看熊| 亚洲美女搞黄| 免费观看久久久久| 亚洲日本在线a| 日本高清视频免费在线观看| 91蜜桃在线视频| 一区二区三区中文字幕精品精品 | 日本最新一区二区三区视频观看| 日本护士...精品国| 久久久五月婷婷| 五月婷婷综合色| 日本精品在线| 亚洲欧美国产毛片在线| www.日本少妇| 在线免费日韩片| 91久久精品日日躁夜夜躁欧美| 免费黄色一级网站| 白嫩亚洲一区二区三区| 日韩亚洲欧美一区二区三区| 曰本三级日本三级日本三级| 国产一区在线电影| 亚洲欧洲国产精品| 我要看一级黄色录像| 综合av在线| 456亚洲影院| 中文字幕黄色av| 国产成人啪免费观看软件| 国产伦精品一区二区三区| 日本中文字幕电影在线观看 | 一区二区三视频| 97caopor国产在线视频| 精品国产乱码久久久久久虫虫漫画| 国产日韩一区二区在线观看| 色999久久久精品人人澡69| 欧美成人r级一区二区三区| 37p粉嫩大胆色噜噜噜| 欧美韩日一区| 97av在线影院| 国产精品天天操| 久久亚洲一级片| 五月天综合婷婷| 六月婷婷综合| 日韩三级电影网址| 91在线无精精品白丝| 午夜精品999| 国产成人一区二| 亚洲AV午夜精品| 久久精品水蜜桃av综合天堂| www.男人天堂网| 国产成人77亚洲精品www| 亚洲爱爱爱爱爱| 久久精品日韩无码| 国产美女一区| caoporn国产精品免费公开| 国产在线日本| 精品福利在线看| 日韩成人av免费| 精品国产a一区二区三区v免费| 欧美精品中文字幕一区| 亚洲精品国产精品乱码视色| www.亚洲国产| 欧美 日韩 国产精品| www.成人在线视频| 日韩成人在线网站| 久久久久久久久久久久久久久久久| 视频一区二区三区在线| 国产一区二区不卡视频| 在线观看av免费| 欧美精品乱人伦久久久久久| 九色porny自拍视频| 亚洲激情专区| 99精品欧美一区二区三区| 日韩美女网站| 欧美在线你懂的| 熟女俱乐部一区二区| 精品动漫3d一区二区三区免费| 成人福利网站在线观看11| 国产在线自天天| 色综合色狠狠天天综合色| 国产免费一区二区三区最新6| 亚洲高清影视| 成人在线视频网站| 日本欧美在线视频免费观看| 欧美日韩一卡二卡三卡| 中文字幕在线观看免费高清| 老妇喷水一区二区三区| 久久国产精品免费一区| 美女av在线免费看| 日韩av在线不卡| 男人操女人的视频网站| 国产在线播放一区三区四| 欧美亚洲视频一区| 伊人久久大香线蕉综合影院首页| 色婷婷综合久久久久| 国产又大又长又粗| 亚洲精品乱码久久久久久黑人| 一级黄色片国产| 中文字幕亚洲综合久久五月天色无吗''| 国产中文字幕亚洲| 国产原创在线观看| 日韩美女主播在线视频一区二区三区 | 久热国产精品视频| www黄色在线观看| 亚洲影院免费观看| 污污内射在线观看一区二区少妇 | 九九热精品在线播放| 久久中文字幕二区| 91美女福利视频高清| 曰本三级在线| 日韩不卡在线观看| 精品国产乱子伦| 国产精品美女久久久久久久久 | 日韩综合在线观看| 国产精品区一区二区三区| 午夜精品久久久久久久99热影院| 综合一区av| 国产欧美韩日| 欧美日韩不卡| 久久深夜福利免费观看| 精品乱子伦一区二区| 性久久久久久久久久久久| 久久中文字幕人妻| 久久99热这里只有精品| 99久久久精品视频| 久久93精品国产91久久综合| 国产日韩欧美在线| 黄页网站在线| 亚洲欧美激情另类校园| 91精品国产乱码久久久久| 亚洲免费色视频| 黄色在线观看av| 久久99久久精品欧美| 欧美激情视频免费看| 国产aⅴ精品一区二区三区久久| 国产精品一区二区在线| 国产盗摄一区二区| 一区二区三区回区在观看免费视频| 国产日韩欧美一区二区东京热| 亚洲大片精品永久免费| 亚洲综合第一区| 99精品热视频| 交换做爰国语对白| 葵司免费一区二区三区四区五区| 欧美xxxx吸乳| 精品一区二区三区中文字幕老牛| 超碰97在线播放| 精品美女一区| 91精品国产91久久久久久久久| 自拍视频在线网| 日韩电影第一页| 国产视频aaa| 在线观看亚洲精品视频| 久久精品国产亚洲AV无码麻豆| 中文字幕高清不卡| 人妻丰满熟妇av无码久久洗澡| 国内一区二区视频| 欧美日韩亚洲自拍| 国产精品夜夜夜| 欧美亚洲黄色片| 亚洲国产成人精品女人| 欧美日韩视频在线一区二区观看视频| 视频一区在线| 91九色国产在线| 日本精品在线中文字幕| 97成人在线视频| 后进极品白嫩翘臀在线播放| 精品国产一区二区三区四区在线观看 | 亚洲爱爱视频| 7777精品视频| tube8在线hd| 欧美多人爱爱视频网站| 久久99精品久久| 这里只有精品在线观看| 免费一级在线观看播放网址| 亚洲国产精品久久| 性做久久久久久久| 日韩一区二区三区视频在线观看| 亚洲一区二区影视| 欧美日韩亚州综合| 一级片在线免费播放| 色婷婷国产精品综合在线观看| www.国产成人| 天天做天天摸天天爽国产一区| 久久精品国产亚洲av麻豆色欲 | 欧美日本三级| 亚洲一区二区三区在线免费观看| 日韩久久99| 成人av电影天堂| 欧美激情精品| 99国精产品一二二线| 日韩精品一区二区三区中文| 亚洲伊人成综合成人网| 国产精品一站二站| 99se婷婷在线视频观看| 在线精品自拍| 久久涩涩网站| 国产在视频线精品视频www666| 欧美久久久久久久| 精品久久久中文字幕| 亚洲巨乳在线观看| 一区二区三区在线观看免费| 成人国产一区二区三区| 在线成人黄色| 97xxxxx| 免费av成人在线| 三年中文在线观看免费大全中国| 狠狠色丁香久久婷婷综合_中| 夜夜爽久久精品91| 成人av午夜影院| 大地资源二中文在线影视观看| 久久久不卡影院| 97精品在线播放| 一二三区精品视频| 日韩av黄色片| 欧亚洲嫩模精品一区三区| 一区二区精品视频在线观看| 69久久夜色精品国产69蝌蚪网| 亚洲欧美高清视频| 亚洲免费小视频| 蜜芽在线免费观看| 97精品视频在线| 97久久网站| 国产精品一区二区三区精品 | 亚洲色图15p| 日本在线免费中文字幕| 欧美国产日本在线| 日韩成人av电影| 亚洲精品欧美极品| 国产不卡一二三区| 亚洲区成人777777精品| 一区二区三区高清视频在线观看| 91在线视频观看免费| 国产精品一二三四五| 插吧插吧综合网| 亚洲日本一区二区三区| 日本中文字幕在线| 制服.丝袜.亚洲.另类.中文| 亚洲色图21p| 萌白酱国产一区二区| 久久夜夜操妹子| 电影午夜精品一区二区三区| 欧美亚洲国产一区| 亚洲人成无码网站久久99热国产| 久久精品久久综合| 污污污www精品国产网站| 国产精品欧美极品| 国产欧美一区二区三区在线看蜜臂| 欧美精品v国产精品v日韩精品| 天堂v视频永久在线播放| 欧美成人激情在线| 国产极品嫩模在线观看91精品| 国产99午夜精品一区二区三区| 日韩免费久久| 欧美性久久久久| 国产v日产∨综合v精品视频| 国产精品酒店视频| 欧美午夜精品久久久久久人妖| 国产激情久久久久久熟女老人av| 亚洲夜晚福利在线观看| 涩涩视频网站在线观看| 亚洲一区二区三区香蕉 | 久久九九久久九九| 日韩精品一区二区不卡| 91精品一区二区三区久久久久久 | 中文字幕制服丝袜成人av| 久久精品国产成人av| 日韩欧美成人激情| 免费**毛片在线| 国产欧美日韩中文| 成人午夜av| 99热手机在线| 国产欧美精品一区aⅴ影院| 成人在线免费看视频| 欧美精品一区二区三区四区 | 日本精品va在线观看| 国产精品17p| 欧美一级免费播放| 国产91丝袜在线观看| 久久久久成人精品无码| 欧美一区二区三区的| av在线网址观看| 亚洲va男人天堂| 亚洲澳门在线| 日韩欧美中文视频| 亚洲综合激情另类小说区| 精品国产亚洲一区二区麻豆| 久久精品视频在线播放| 自拍偷拍亚洲图片| 日本丰满大乳奶| 国产黄色91视频| 久久精品国产亚洲AV无码麻豆| 亚洲第一区第一页| 久久男人天堂| 欧美性bbwbbwbbwhd| 日韩va亚洲va欧美va久久| 天堂在线中文视频| 欧美日韩一区二区在线观看 | 欧美日韩国产传媒| 国产精品人人妻人人爽人人牛| 国产日产欧美一区二区三区| 成人黄色三级视频| 少妇高潮久久77777| 精品国产亚洲一区二区三区在线| 男人草女人视频| 丁香五精品蜜臀久久久久99网站| 日韩免费不卡视频| 亚洲人成网7777777国产| 国产成人精品一区二区三区免费| 亚洲欧美成人一区| 国产精品一区二区久久精品爱涩 | 国产日韩一区| 成熟人妻av无码专区| 欧美美女一区二区三区| gogo在线高清视频| 久久久影院一区二区三区| 免费欧美日韩国产三级电影| 国产探花在线免费观看| 亚洲精品suv精品一区二区| 免费观看一级欧美片| 一区二区视频在线播放| 成人18视频日本| 真实新婚偷拍xxxxx| 欧美黑人xxxⅹ高潮交| 国产综合久久久| 三级黄色片播放| 色婷婷综合久久久久中文| 国产精品一区二区三区视频网站| 国产高清一区二区三区| 日本欧美一区二区| 极品盗摄国产盗摄合集| 亚洲色图狂野欧美| 国产精品久久久久久久久久辛辛| 日韩欧美一区三区| 亚洲视频1区2区| 视频国产在线观看| 91中文精品字幕在线视频| 中文在线不卡| 欧美成人黄色网| 亚洲午夜精品久久久久久久久久久久| 欧美久久亚洲| 国产九九热视频|