欧美日韩激情_美女国产一区_国产精品久久久久影院日本_69xxx在线

SpringCloudStream-構建消息事件驅動的微服務

  • 承接上文:Spring Cloud Alibaba RocketMQ - 構建異步通信的微服務

Spring Cloud Stream簡介

Spring Cloud Stream是什么:

目前創新互聯公司已為數千家的企業提供了網站建設、域名、虛擬空間、綿陽服務器托管、企業網站設計、亞東網站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協力一起成長,共同發展。

Spring Cloud Stream是Spring Cloud的一個子項目,是一個能讓我們更加方便操作MQ的框架,其目的用于構建與消息中間件連接的高度可伸縮的消息事件驅動的微服務

簡單來說Spring Cloud Stream就是一個簡化了MQ操作的框架,其架構圖如下:
Spring Cloud Stream - 構建消息事件驅動的微服務

  • 圖片來自官方文檔,從圖中可以看到應用通過input和output與Binder進行交互,而Binder是一個讓我們的微服務與MQ集成的組件。圖中的Middleware即是消息中間件,目前支持Kafka、RabbitMQ以及RocketMQ

Spring Cloud Stream編程模型:
Spring Cloud Stream - 構建消息事件驅動的微服務

  • 圖片來自官方文檔,微服務(Application)集成了Stream后,Stream的Destination Binder會創建兩個Binding,左邊的Binding連接著RabbitMQ,右邊的Binding連接著Kafka。左邊的Binding從RabbitMQ消費消息,然后經過圖中代碼的處理后,把處理結果通過右邊的Binding投遞到Kafka。簡單來說,就是這個微服務消費了RabbitMQ里的消息并對其進行處理,最后將處理的結果投遞到Kafka中。Input和Output是消息相對與微服務的走向,input表示微服務接收消息,output表示微服務投遞消息或發送消息

關于圖中的概念:

  • Destination Binder(目標綁定器):與消息中間件通信的組件,用于實現消息的消費和投遞
  • Destination Bindings(目標綁定):Binding是連接應用程序跟消息中間件的橋梁,用于消息的消費和生產,由binder創建

使用Spring Cloud Stream

現在有一個微服務項目:content-center,該微服務作為生產者,我們來為這個微服務集成Spring Cloud Stream,第一步添加stream依賴:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
  • Tips:該項目的Spring Cloud版本為:Greenwich.SR1;Spring Cloud Alibaba版本為:2.1.0.RELEASE

第二步,在啟動類上添加@EnableBinding注解,如下:

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;

@EnableBinding(Source.class)
...

第三步,在配置文件中,添加與stream相關的配置項:

spring:
  cloud:
    stream:
      rocketmq:
        binder:
          name-server: 192.168.190.129:9876
      bindings:
        # 生產者為output
        output:
          # 用于指定topic
          destination: stream-test-topic

完成以上步驟后,項目就已經集成了Spring Cloud Stream,現在我們來使用Spring Cloud Stream編寫生產者,具體代碼如下:

package com.zj.node.contentcenter.controller.content;

import lombok.RequiredArgsConstructor;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 生產者
 *
 * @author 01
 * @date 2019-08-10
 **/
@RestController
@RequiredArgsConstructor
public class TestProducerController {

    private final Source source;

    @GetMapping("/test-stream")
    public String testStream(){
        Message<String> message = MessageBuilder
                .withPayload("消息體")
                .build();
        source.output()
                .send(message);

        return "send message success!";
    }
}

啟動項目,測試該接口是否能成功執行:
Spring Cloud Stream - 構建消息事件驅動的微服務


然后為另一個作為消費者的微服務項目:user-center,集成Spring Cloud Stream,由于依賴配置是一樣的,這里就不進行重復了,但是配置和注解里的類需要更改一下。首先是配置如下:

spring:
  cloud:
    stream:
      rocketmq:
        binder:
          name-server: 192.168.190.129:9876
      bindings:
        # 消費者為input
        input:
          # 用于指定topic
          destination: stream-test-topic
          # rocketmq必須配置group,否則啟動會報錯
          # 如果使用的是其他MQ,則不是必須配置的
          group: binder-group

啟動類的注解如下:

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Sink;

@EnableBinding(Sink.class)
...

完成集成后,使用Spring Cloud Stream編寫消費者,具體代碼如下:

package com.zj.node.usercenter.rocketmq;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.stereotype.Service;

/**
 * 消費者
 *
 * @author 01
 * @date 2019-08-10
 **/
@Slf4j
@Service
public class TestStreamConsumer {

    @StreamListener(Sink.INPUT)
    public void receive(String messageBody) {
        log.info("通過stream收到了消息,messageBody = {}", messageBody);
    }
}

完成代碼的編寫后啟動項目,由于先前我們已經通過生產者往RocketMQ投遞了消息,所以此時控制臺會輸出接收到的消息,如下:
Spring Cloud Stream - 構建消息事件驅動的微服務


Spring Cloud Stream自定義接口

通過以上小節的學習,我們已經了解了Spring Cloud Stream的基本使用。從以上示例可以得知,input用于綁定一個topic消費消息,output則反之,用于綁定一個topic投遞消息。

但在實際的項目中,可能會有多個topic,甚至在極端場景下,不同的topic可能使用不同的MQ實現,而stream默認提供的input和output都只能綁定一個topic,所以這個時候就需要用到stream的自定義接口來實現多個“input”和“output”綁定不同的topic了。

在以上小節的示例中可以得知,生產者發送消息時使用的是Source接口里的output方法,而消費者發送消息時使用的是Sink接口里的input方法,并且都需要配置到啟動類的@EnableBinding注解里。所以實際上我們需要自定義接口的源碼與這兩個接口的源碼幾乎一致,只是名稱有所不同而已,使用上也只是將SourceSink改為自定義的接口即可。

接下來簡單演示一下如何自定義接口并使用,我們基于上一小節的例子進行改造。首先是生產者,定義一個用于發送消息的接口,具體代碼如下:

package com.zj.node.contentcenter.rocketmq;

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;

/**
 * 自定義發送消息接口,與stream默認提供的Source源碼是類似的
 *
 * @author 01
 * @date 2019-08-10
 **/
public interface MySource {

    /**
     * Name of the output channel.
     */
    String MY_OUTPUT = "my-output";

    /**
     * @return output channel
     */
    @Output(MY_OUTPUT)
    MessageChannel output();
}

然后在啟動類的@EnableBinding中,添加這個接口:

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;

@EnableBinding({Source.class, MySource.class})
...

在配置文件中添加如下配置:

spring:
  cloud:
    stream:
      rocketmq:
        binder:
          name-server: 192.168.190.129:9876
      bindings:
        # 生產者為output
        output:
          # 用于指定topic
          destination: stream-test-topic
        # 自定義的”output“,這里的名稱需要與MySource接口里的MY_OUTPUT相對應  
        my-output:
          # 綁定不同的topic
          destination: stream-my-topic          

修改生產者的代碼如下即可:

package com.zj.node.contentcenter.controller.content;

import com.zj.node.contentcenter.rocketmq.MySource;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 生產者
 *
 * @author 01
 * @date 2019-08-03
 **/
@RestController
@RequiredArgsConstructor
public class TestProducerController {

    private final MySource mySource;

    @GetMapping("/test-stream")
    public String testStream(){
        Message<String> message = MessageBuilder
                .withPayload("消息體")
                .build();
        mySource.output()
                .send(message);

        return "send message success!";
    }
}

然后啟動項目訪問該接口,測試消息是否能正常發送:
Spring Cloud Stream - 構建消息事件驅動的微服務


改造完生產者后接著改造消費者,首先定義一個用于消費消息的接口,具體代碼如下:

package com.zj.node.usercenter.rocketmq;

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;

/**
 * 自定義消費消息接口,與stream默認提供的Sink源碼是類似的
 *
 * @author 01
 * @date 2019-08-10
 **/
public interface MySink {

    /**
     * Input channel name.
     */
    String MY_INPUT = "my-input";

    /**
     * @return input channel.
     */
    @Input(MY_INPUT)
    SubscribableChannel input();
}

同樣需要在啟動類的@EnableBinding中,添加這個接口:

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Sink;

@EnableBinding({Sink.class, MySink.class})
...

在配置文件中添加如下配置:

spring:
  cloud:
    stream:
      rocketmq:
        binder:
          name-server: 192.168.190.129:9876
      bindings:
        # 消費者為input
        input:
          # 用于指定topic
          destination: stream-test-topic
          # rocketmq必須配置group,否則啟動會報錯
          # 如果使用的是其他MQ,則不是必須配置的
          group: binder-group
        # 自定義的”input“,這里的名稱需要與MySink接口里的MY_INPUT相對應    
        my-input:
          # 綁定不同的topic
          destination: stream-my-topic
          group: my-group

修改消費者的代碼如下:

package com.zj.node.usercenter.rocketmq;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Service;

/**
 * 消費者
 *
 * @author 01
 * @date 2019-08-10
 **/
@Slf4j
@Service
public class TestStreamConsumer {

    @StreamListener(MySink.MY_INPUT)
    public void receive(String messageBody) {
        log.info("自定義接口 - 通過stream收到了消息,messageBody = {}", messageBody);
    }
}

啟動項目,由于先前我們已經通過生產者往RocketMQ投遞了消息,所以此時控制臺會輸出接收到的消息,如下:
Spring Cloud Stream - 構建消息事件驅動的微服務


Spring Cloud Stream的監控

我們都知道Spring Boot Actuator組件用于暴露監控端點,很多監控工具都需要依賴該組件的監控端點實現監控。而項目集成了Stream及Actuator后也會暴露相應的監控端點,首先需要在項目里集成Actuator,添加依賴如下:

<!-- actuator -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在配置文件中添加如下配置:

management:
  endpoints:
    web:
      exposure:
        # 暴露所有監控端點
        include: '*'
  endpoint:
    health:
      # 顯示健康檢測詳情
      show-details: always

訪問http://127.0.0.1:{項目端口}/actuator可以獲取所有暴露出來的監控端點,Stream的相關監控端點也在其列,如下圖:
Spring Cloud Stream - 構建消息事件驅動的微服務

/actuator/bindings端點可以用于查看bindings相關信息:
Spring Cloud Stream - 構建消息事件驅動的微服務

/actuator/channels端點用于查看channels的相關信息,而“input”和“output”就是所謂的channel,可以認為這些channel是topic的抽象:
Spring Cloud Stream - 構建消息事件驅動的微服務

/actuator/health端點中可以查看binder及RocketMQ的狀態,主要是用于查看MQ的連接情況,如果連接不上其status則為DOWN:
Spring Cloud Stream - 構建消息事件驅動的微服務


Spring Cloud Stream + RocketMQ實現事務消息

先前在Spring Cloud Alibaba RocketMQ - 構建異步通信的微服務一文的末尾中,我們介紹了RocketMQ的事務消息并且也演示了如何編碼實現。在本文學習了Spring Cloud Stream之后,我們來結合Stream對之前實現事務消息的代碼進行重構。

首先修改配置文件如下:

spring:
  cloud:
    stream:
      rocketmq:
        binder:
          name-server: 192.168.190.129:9876
        bindings:
          output:
            producer:
              # 開啟事務消息,這樣通過output這個channel發送的消息都是半消息
              transactional: true
              # 生產者所在的事務組名稱
              group: tx-test-producer-group
      bindings:
        # 生產者為output
        output:
          # 用于指定topic
          destination: stream-test-topic

然后重構TestProducerService,具體代碼如下:

package com.zj.node.contentcenter.service.test;

import com.alibaba.fastjson.JSON;
import com.zj.node.contentcenter.dao.content.NoticeMapper;
import com.zj.node.contentcenter.dao.log.RocketmqTransactionLogMapper;
import com.zj.node.contentcenter.domain.entity.content.Notice;
import com.zj.node.contentcenter.domain.entity.log.RocketmqTransactionLog;
import lombok.RequiredArgsConstructor;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

/**
 * @author 01
 * @date 2019-08-08
 **/
@Service
@RequiredArgsConstructor
public class TestProducerService {

    private final NoticeMapper noticeMapper;
    private final RocketmqTransactionLogMapper rocketmqTransactionLogMapper;
    private final Source source;

    public String testSendMsg(Notice notice) {
        // 生成事務id
        String transactionId = UUID.randomUUID().toString();
        // 通過stream發送消息,這里實際發送的就是半消息
        source.output().send(
                MessageBuilder.withPayload("消息體")
                        // header是消息的頭部分,可以用作傳參
                        .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                        .setHeader("notice_id", notice.getId())
                        // 對象需要轉換成json,否則默認是調用對象的toString方法轉換為字符串
                        .setHeader("notice", JSON.toJSONString(notice))
                        .build()
        );

        return "send message success";
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateNotice(Integer noticeId, Notice notice) {
        Notice newNotice = new Notice();
        newNotice.setId(noticeId);
        newNotice.setContent(notice.getContent());

        noticeMapper.updateByPrimaryKeySelective(newNotice);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateNoticeWithRocketMQLog(Integer noticeId, Notice notice, String transactionId) {
        updateNotice(noticeId, notice);
        // 寫入事務日志
        rocketmqTransactionLogMapper.insertSelective(
                RocketmqTransactionLog.builder()
                        .transactionId(transactionId)
                        .log("updateNotice")
                        .build()
        );
    }
}

最后是重構TestTransactionListener,具體代碼如下:

package com.zj.node.contentcenter.rocketmq;

import com.alibaba.fastjson.JSON;
import com.zj.node.contentcenter.dao.log.RocketmqTransactionLogMapper;
import com.zj.node.contentcenter.domain.entity.content.Notice;
import com.zj.node.contentcenter.domain.entity.log.RocketmqTransactionLog;
import com.zj.node.contentcenter.service.test.TestProducerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;

/**
 * 本地事務監聽器
 *
 * @author 01
 * @date 2019-08-08
 **/
@Slf4j
@RequiredArgsConstructor
// 這里的txProducerGroup需要與配置文件里配置的一致
@RocketMQTransactionListener(txProducerGroup = "tx-test-producer-group")
public class TestTransactionListener implements RocketMQLocalTransactionListener {

    private final TestProducerService service;
    private final RocketmqTransactionLogMapper rocketmqTransactionLogMapper;

    /**
     * 用于執行本地事務的方法
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        MessageHeaders headers = msg.getHeaders();
        String transactionId = (String) headers.get(RocketMQHeaders.TRANSACTION_ID);
        log.info("執行本地事務方法. 事務id: {}", transactionId);
        Integer noticeId = Integer.parseInt((String) headers.get("notice_id"));
        // 由于從header里獲取的對象是json格式所以需要進行轉換
        Notice notice = JSON.parseObject((String) headers.get("notice"), Notice.class);

        try {
            // 執行帶有事務注解的方法
            service.updateNoticeWithRocketMQLog(noticeId, notice, transactionId);
            // 正常執行向MQ Server發送commit消息
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
            log.error("本地事務方法發生異常,消息將被回滾", e);
            // 發生異常向MQ Server發送rollback消息
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }

    /**
     * 用于回查本地事務的執行結果
     */
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        MessageHeaders headers = msg.getHeaders();
        String transactionId = (String) headers.get(RocketMQHeaders.TRANSACTION_ID);
        log.warn("回查本地事務狀態. 事務id: {}", transactionId);

        // 按事務id查詢日志數據
        RocketmqTransactionLog transactionLog = rocketmqTransactionLogMapper.selectOne(
                RocketmqTransactionLog.builder()
                        .transactionId(transactionId)
                        .build()
        );

        // 如果能按事務id查詢出來數據表示本地事務執行成功,沒有數據則表示本地事務執行失敗
        if (transactionLog == null) {
            log.warn("本地事務執行失敗,事務日志不存在,消息將被回滾. 事務id: {}", transactionId);
            return RocketMQLocalTransactionState.ROLLBACK;
        }
        return RocketMQLocalTransactionState.COMMIT;
    }
}

擴展文章:

  • Spring Cloud Stream實現消息過濾的三種主要方式
  • Spring Cloud Stream異常處理
  • Spring Cloud Stream總結

網站欄目:SpringCloudStream-構建消息事件驅動的微服務
鏈接URL:http://m.kartarina.com/article46/gdjgeg.html

成都網站建設公司_創新互聯,為您提供網站營銷軟件開發、網站策劃、定制開發、云服務器、網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

網站建設網站維護公司
欧美日韩激情_美女国产一区_国产精品久久久久影院日本_69xxx在线
亚洲欧洲在线观看av| 67194成人在线观看| 激情六月婷婷久久| 日韩制服丝袜av| 午夜久久久久久久久| 亚洲国产aⅴ成人精品无吗| 亚洲免费观看高清| 亚洲精品日韩专区silk| 亚洲一卡二卡三卡四卡五卡| 亚洲综合激情小说| 亚洲国产日产av| 青青青伊人色综合久久| 久久91精品久久久久久秒播| 精品一区二区日韩| 成人性生交大片免费看中文| 成人av在线资源网站| 在线观看欧美精品| 欧美高清视频www夜色资源网| 欧美午夜影院一区| 欧美一区二区三区不卡| 久久精品夜夜夜夜久久| 中文字幕中文在线不卡住| 亚洲一区二区视频在线观看| 日韩不卡免费视频| 国产一区二区三区在线看麻豆| 国产99精品在线观看| 91福利国产成人精品照片| 欧美久久高跟鞋激| 久久久久久久性| 亚洲最色的网站| 国产一区视频导航| 日本精品视频一区二区| 欧美一区二区三区免费大片| 国产精品理论片| 五月天婷婷综合| 成人黄色电影在线| 91麻豆精品国产91久久久久| 国产精品情趣视频| 日韩国产欧美视频| 不卡的电视剧免费网站有什么| 欧美日韩久久一区| 综合分类小说区另类春色亚洲小说欧美| 欧洲另类一二三四区| 欧美一级在线视频| 一区二区三区不卡在线观看| 久久成人久久爱| 日本韩国精品一区二区在线观看| 理论片日本一区| 91国偷自产一区二区三区观看| 精品国产成人在线影院| 欧美成人一级视频| 18成人在线观看| 国内精品伊人久久久久av影院| 91丨九色丨黑人外教| wwwwxxxxx欧美| 日本人妖一区二区| 欧洲国内综合视频| 国产精品午夜免费| 国产福利91精品一区二区三区| 欧美日韩dvd在线观看| 亚洲免费色视频| www.日韩精品| 国产精品久久毛片a| 韩国v欧美v亚洲v日本v| 欧美丰满少妇xxxbbb| 亚洲综合区在线| 91高清视频免费看| 亚洲欧美色综合| 91激情五月电影| 亚洲欧洲制服丝袜| 91国内精品野花午夜精品| 亚洲欧美福利一区二区| 99re在线精品| 亚洲人123区| 欧美亚洲国产一区二区三区va | 免费成人av在线| 欧美精品自拍偷拍动漫精品| 亚洲高清久久久| 91国偷自产一区二区开放时间 | 国产成人免费视频网站高清观看视频 | 欧美日韩国产高清一区二区| 亚洲午夜成aⅴ人片| 欧美四级电影在线观看| 午夜视频一区在线观看| 91精品中文字幕一区二区三区| 日本怡春院一区二区| 日韩午夜在线观看| 国产原创一区二区| 亚洲国产精品精华液ab| www.性欧美| 亚洲高清三级视频| 91精品国产色综合久久| 极品少妇一区二区三区精品视频| 久久精品一区蜜桃臀影院| 成人高清伦理免费影院在线观看| 一色屋精品亚洲香蕉网站| 色就色 综合激情| 香蕉久久一区二区不卡无毒影院| 日韩欧美一级二级| 福利91精品一区二区三区| 亚洲欧美日韩人成在线播放| 欧洲一区二区三区在线| 日本欧美一区二区三区乱码| 亚洲精品一区二区三区精华液 | 国产一区 二区| 中文字幕在线免费不卡| 欧美性大战xxxxx久久久| 久久福利视频一区二区| 国产精品美女久久久久av爽李琼| 亚洲午夜精品在线| 精品盗摄一区二区三区| av一二三不卡影片| 日韩二区在线观看| 中文字幕一区二区三区在线播放| 日韩精品免费视频人成| 国产拍揄自揄精品视频麻豆| 在线观看欧美精品| 国产剧情一区二区| 日韩高清在线观看| 日韩一区在线免费观看| 日韩久久免费av| 欧美性极品少妇| 成人动漫一区二区| 极品少妇一区二区三区精品视频| 亚洲小说欧美激情另类| 国产欧美日韩在线看| 日韩欧美高清一区| 在线免费观看日韩欧美| 国产91精品精华液一区二区三区 | 欧美视频在线观看一区| 国产一区二区三区高清播放| 亚洲成a人v欧美综合天堂下载| 国产三级三级三级精品8ⅰ区| 91精品国产综合久久福利软件| 91视频免费观看| 成人a免费在线看| 国产精品一区免费在线观看| 美女精品自拍一二三四| 亚洲一区日韩精品中文字幕| 91麻豆精品视频| 成人av手机在线观看| 国产揄拍国内精品对白| 美女一区二区久久| 免费成人美女在线观看.| 午夜激情一区二区| 亚洲主播在线播放| 一区二区三区在线看| 中文字幕在线不卡国产视频| 中文在线一区二区| 国产区在线观看成人精品| 久久久影视传媒| 99精品国产91久久久久久| 国产美女主播视频一区| 美女视频一区二区三区| 欧美96一区二区免费视频| 亚洲成人中文在线| 丝袜a∨在线一区二区三区不卡| 亚洲国产成人av网| 日韩电影在线一区二区三区| 日韩国产欧美在线观看| 中文字幕一区二区三区视频| 欧美国产激情一区二区三区蜜月| 国产亚洲欧洲997久久综合| 成人亚洲一区二区一| 99久久99久久综合| 色系网站成人免费| 欧美色手机在线观看| 欧美一级搡bbbb搡bbbb| 精品国产乱码久久久久久浪潮 | 国产精品久久久久久久久免费桃花 | 亚洲国产美国国产综合一区二区| 亚洲国产欧美在线| 极品销魂美女一区二区三区| 成人国产精品免费| 欧美午夜寂寞影院| 精品国产免费一区二区三区四区 | 五月综合激情日本mⅴ| 奇米一区二区三区| 国产高清精品在线| 在线免费精品视频| 久久久亚洲精华液精华液精华液| 国产精品久久久久久久久图文区| 亚洲成av人片一区二区| 狠狠久久亚洲欧美| 日本道色综合久久| 精品少妇一区二区三区日产乱码| 国产精品色婷婷久久58| 午夜电影一区二区| k8久久久一区二区三区| 欧美军同video69gay| 91视频精品在这里| 91麻豆精品国产综合久久久久久| 国产精品欧美一区二区三区| 亚洲成人黄色小说| 成人黄色在线视频| 337p日本欧洲亚洲大胆精品| 亚洲一区二区四区蜜桃| 成人一区在线观看| 精品女同一区二区| 亚洲午夜一区二区三区|