Spring Cloud1

Spring Cloud

代碼地址:https://github.com/jedyang/springCloud

springcloud中文社區(qū)給的定義是微服務(wù)架構(gòu)集大成者,云計(jì)算最佳業(yè)務(wù)實(shí)踐
我的理解是分布式服務(wù)全家桶。
如果你有dubbo或其他分布式框架的使用經(jīng)驗(yàn),那么對(duì)springcloud提供的特性是很好理解的。
springcloud提供了如下特性:

  • 分布式配置
  • 服務(wù)注冊(cè)和發(fā)現(xiàn)
  • 路由
  • 遠(yuǎn)程服務(wù)調(diào)用
  • 負(fù)載均衡
  • 斷路器
  • 全局鎖
  • 主從選舉和集群狀態(tài)
  • 分布式消息

主要項(xiàng)目

spring cloud config

springcloud的配置管理項(xiàng)目,使用git管理。可根據(jù)不同環(huán)境管理不同參數(shù)。也可用于非spring應(yīng)用。

Spring Cloud Netflix

Spring Cloud包含了非常多的子框架,其中,Spring Cloud Netflix是其中一套框架,由Netflix開發(fā)后來又并入Spring Cloud大家庭,它主要提供的模塊包括:服務(wù)發(fā)現(xiàn)(Eureka),斷路器(Hystrix),智能路由(Zuul)和客戶端負(fù)載平衡(Ribbon)。

Spring Cloud Bus

事件總線。使用分布式消息將服務(wù)和服務(wù)實(shí)例聯(lián)系起來。在集群的狀態(tài)變化傳播中作用很大。

Spring Cloud for Cloud Foundry

讓你的應(yīng)用同Cloudfoundry進(jìn)行整合。(Cloudfoundry是最近很熱的開源PaaS云平臺(tái))。讓你很容易實(shí)現(xiàn)SSO(單點(diǎn)登錄)、OAuth2(一個(gè)關(guān)于授權(quán)的開放網(wǎng)絡(luò)標(biāo)準(zhǔn))功能,以及Cloudfoundry的服務(wù)分發(fā)器。

Spring Cloud Cloud Foundry Service Broker

提供了一個(gè)擴(kuò)展點(diǎn),以便于開發(fā)基于 Cloud Foundry管理的服務(wù)分發(fā)器。

Spring Cloud Cluster

主從選舉。基于zookeeper,redis,hazelcast(hazelcast是一個(gè)開放源碼集群和高度可擴(kuò)展的數(shù)據(jù)分發(fā)平臺(tái)),consul(支持多數(shù)據(jù)中心下,分布式高可用的,服務(wù)發(fā)現(xiàn)和配置共享)的抽象和實(shí)現(xiàn)。

Spring Cloud Consul

基于Consul實(shí)現(xiàn)的服務(wù)發(fā)現(xiàn)和配置管理

Spring Cloud Security

提供了對(duì)OAuth2 負(fù)載均衡的客戶端,以及基于Zuul代理的頭部校驗(yàn)。

Spring Cloud Sleuth

對(duì)spring cloud分布式應(yīng)用的服務(wù)鏈路追蹤

Spring Cloud Data Flow

一個(gè)建立數(shù)據(jù)集成和實(shí)時(shí)處理管道的工具集。
簡(jiǎn)化了應(yīng)用程序的開發(fā)和部署 將精力集中到數(shù)據(jù)處理的用例上。

Spring Cloud Stream

一個(gè)輕量級(jí)的事件驅(qū)動(dòng)的微服務(wù)框架。可以快速構(gòu)建應(yīng)用和外部系統(tǒng)對(duì)接。可以在springboot應(yīng)用之間通過簡(jiǎn)單的聲明模型,基于kafka或rabbitMq交互消息。

Spring Cloud Stream App Starters

一個(gè)基于springboot的同外部系統(tǒng)的集成應(yīng)用

Spring Cloud Task

短時(shí)任務(wù)處理框架。如定時(shí)任務(wù)。

Spring Cloud Task App Starters

對(duì)應(yīng)的具體應(yīng)用。

Spring Cloud for Amazon Web Services

方便同AWS服務(wù)集成

Spring Cloud Connectors

使各種PaaS平臺(tái)應(yīng)用連接基礎(chǔ)后端服務(wù)(如數(shù)據(jù)庫服務(wù)、消息中間件)更容易。

Spring Cloud Starters

用于使基于springcloud的依賴管理更方便

Spring Cloud CLI

是一個(gè)插件,可以用groovy語言快速創(chuàng)建spring cloud應(yīng)用

Spring Cloud Contract

是一個(gè)消費(fèi)者驅(qū)動(dòng)的、面向Java的契約框架。

Spring Cloud Netflix

Netflix是spring cloud的核心框架,必學(xué)必用。

微服務(wù)架構(gòu)

首先,我們來看看一般的微服務(wù)架構(gòu)需要的功能或使用場(chǎng)景:

  1. 我們把整個(gè)系統(tǒng)根據(jù)業(yè)務(wù)拆分成幾個(gè)子系統(tǒng)。

  2. 每個(gè)子系統(tǒng)可以部署多個(gè)應(yīng)用,多個(gè)應(yīng)用之間使用負(fù)載均衡。

  3. 需要一個(gè)服務(wù)注冊(cè)中心,所有的服務(wù)都在注冊(cè)中心注冊(cè),負(fù)載均衡也是通過在注冊(cè)中心注冊(cè)的服務(wù)來使用一定策略來實(shí)現(xiàn)。

  4. 所有的客戶端都通過同一個(gè)網(wǎng)關(guān)地址訪問后臺(tái)的服務(wù),通過路由配置,網(wǎng)關(guān)來判斷一個(gè)URL請(qǐng)求由哪個(gè)服務(wù)處理。請(qǐng)求轉(zhuǎn)發(fā)到服務(wù)上的時(shí)候也使用負(fù)載均衡。

  5. 服務(wù)之間有時(shí)候也需要相互訪問。例如有一個(gè)用戶模塊,其他服務(wù)在處理一些業(yè)務(wù)的時(shí)候,要獲取用戶服務(wù)的用戶數(shù)據(jù)。

  6. 需要一個(gè)斷路器,及時(shí)處理服務(wù)調(diào)用時(shí)的超時(shí)和錯(cuò)誤,防止由于其中一個(gè)服務(wù)的問題而導(dǎo)致整體系統(tǒng)的癱瘓。

  7. 還需要一個(gè)監(jiān)控功能,監(jiān)控每個(gè)服務(wù)調(diào)用花費(fèi)的時(shí)間等。

Netflix

Spring Cloud Netflix框架剛好就滿足了上面所有的需求,而且最重要的是,使用起來非常的簡(jiǎn)單。Spring Cloud Netflix包含的組件及其主要功能大致如下:

  1. Eureka,服務(wù)注冊(cè)和發(fā)現(xiàn),它提供了一個(gè)服務(wù)注冊(cè)中心、服務(wù)發(fā)現(xiàn)的客戶端,還有一個(gè)方便的查看所有注冊(cè)的服務(wù)的界面。 所有的服務(wù)使用Eureka的服務(wù)發(fā)現(xiàn)客戶端來將自己注冊(cè)到Eureka的服務(wù)器上。

  2. Zuul,網(wǎng)關(guān),所有的客戶端請(qǐng)求通過這個(gè)網(wǎng)關(guān)訪問后臺(tái)的服務(wù)。他可以使用一定的路由配置來判斷某一個(gè)URL由哪個(gè)服務(wù)來處理。并從Eureka獲取注冊(cè)的服務(wù)來轉(zhuǎn)發(fā)請(qǐng)求。

  3. Ribbon,即負(fù)載均衡,Zuul網(wǎng)關(guān)將一個(gè)請(qǐng)求發(fā)送給某一個(gè)服務(wù)的應(yīng)用的時(shí)候,如果一個(gè)服務(wù)啟動(dòng)了多個(gè)實(shí)例,就會(huì)通過Ribbon來通過一定的負(fù)載均衡策略來發(fā)送給某一個(gè)服務(wù)實(shí)例。

  4. Feign,服務(wù)客戶端,服務(wù)之間如果需要相互訪問,可以使用RestTemplate,也可以使用Feign客戶端訪問。它默認(rèn)會(huì)使用Ribbon來實(shí)現(xiàn)負(fù)載均衡。

  5. Hystrix,監(jiān)控和斷路器。我們只需要在服務(wù)接口上添加Hystrix標(biāo)簽,就可以實(shí)現(xiàn)對(duì)這個(gè)接口的監(jiān)控和斷路器功能。

  6. Hystrix Dashboard,監(jiān)控面板,他提供了一個(gè)界面,可以監(jiān)控各個(gè)服務(wù)上的服務(wù)調(diào)用所消耗的時(shí)間等。

  7. Turbine,監(jiān)控聚合,使用Hystrix監(jiān)控,我們需要打開每一個(gè)服務(wù)實(shí)例的監(jiān)控信息來查看。而Turbine可以幫助我們把所有的服務(wù)實(shí)例的監(jiān)控信息聚合到一個(gè)地方統(tǒng)一查看。這樣就不需要挨個(gè)打開一個(gè)個(gè)的頁面一個(gè)個(gè)查看。

接下來一個(gè)一個(gè)看。

Eureka

作為服務(wù)注冊(cè)與發(fā)現(xiàn)的中心。我們的demo分為兩部分,一個(gè)server,一個(gè)client。 這里的server是指注冊(cè)中心。client是指向注冊(cè)中心注冊(cè)或者訂閱服務(wù)的消費(fèi)者。

  1. 創(chuàng)建一個(gè)maven主工程

  2. 建一個(gè)server模塊。
    右鍵-->new module -->Spring Initializr -->next
    -->填寫相關(guān)信息-->next
    -->dependencies 選Cloud Discovery-->Eureka Server
    -->finish

  3. 第一個(gè)server

     // 服務(wù)注冊(cè)中心注解
     @EnableEurekaServer
     @SpringBootApplication
     public class ServerApplication {
     
         public static void main(String[] args) {
             SpringApplication.run(ServerApplication.class, args);
         }
     }
    

    代碼非常簡(jiǎn)單,就是在原來springboot的啟動(dòng)類上加了一個(gè)注解。
    @EnableEurekaServer
    將該實(shí)例注冊(cè)為一個(gè)Eureka的server角色。

  4. 配置文件
    在resources下建一個(gè)appication.yml
    配置如下:
    server:
    port: 8761

     eureka:
       instance:
         hostname: localhost
       client:
         registerWithEureka: false
         fetchRegistry: false
         serviceUrl:
           defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    

(注意,yml對(duì)于格式要求非常嚴(yán)格,縮進(jìn)不要搞錯(cuò))

  1. 啟動(dòng)工程
    訪問http://localhost:8761。可以看到注冊(cè)中心的界面。
    此時(shí)還沒有服務(wù)提供者注冊(cè)過來。
1.png
  1. 同創(chuàng)建server一樣的步驟,建一個(gè)client

  2. 代碼如下

     @SpringBootApplication
     @EnableEurekaClient
     @RestController
     public class ClientApplication {
     
         @Value("${server.port}")
         String port;
         @RequestMapping("/hi")
         public String home(@RequestParam String name) {
             return "hi "+name+",i am from port:" +port;
         }
     
         public static void main(String[] args) {
             SpringApplication.run(ClientApplication.class, args);
         }
     }
    

    @EnableEurekaClient表明這是一個(gè)client

  3. 配置文件

     eureka:
       client:
         serviceUrl:
           defaultZone: http://localhost:8761/eureka/
     server:
       port: 8762
     spring:
       application:
         name: service-hi
    
  4. 啟動(dòng)工程
    查看http://localhost:8761已經(jīng)注冊(cè)進(jìn)來

2.png

配置文件中spring.application.name指定的name就是注冊(cè)的服務(wù)名。
其他應(yīng)用調(diào)用也是根據(jù)這個(gè)name來找。

ribbon+restTemplate

微服務(wù)架構(gòu)中,業(yè)務(wù)被拆分成單獨(dú)的服務(wù),服務(wù)之間通過rest相互調(diào)用。在springcloud中有兩種調(diào)用方式:ribbon+restTemplate和feign。
ribbon是一個(gè)負(fù)載均衡客戶端,可以很好的控制http和tcp之上的行為,feign也是使用ribbon的。

  1. 再啟動(dòng)一個(gè)進(jìn)程
    為了嘗試負(fù)載均衡,基于上面的工程。改一下client的配置端口,將8762改為8763再啟動(dòng)一個(gè)服務(wù)提供方client。
    tips:idea默認(rèn)run 是單實(shí)例的,所以再次run main會(huì)讓你停掉之前的服務(wù)。其實(shí)在run configration中配置一下,把Single instance only選項(xiàng)勾掉就可以了。

  2. 查看注冊(cè)中心
    測(cè)試應(yīng)該看到

3.png

已經(jīng)有兩個(gè)服務(wù)注冊(cè)進(jìn)來了。

  1. 建一個(gè)服務(wù)消費(fèi)者
    新建一個(gè)springboot工程:service-consumer
    在dependency時(shí)勾選web、ribbon、eureka discovery

  2. 在resources下新建application.yml
    配置:

     eureka:
       client:
         serviceUrl:
           defaultZone: http://localhost:8761/eureka/
     server:
       port: 8764
     spring:
       application:
         name: service-consumer
    
  3. 修改啟動(dòng)類

     @SpringBootApplication
     @EnableDiscoveryClient
     public class ServicveConsumerApplication {
     
         public static void main(String[] args) {
             SpringApplication.run(ServicveConsumerApplication.class, args);
         }
     
         @Bean
         @LoadBalanced
         RestTemplate restTemplate() {
             return new RestTemplate();
         }
     }
    

    注解@EnableDiscoveryClient作用是向注冊(cè)中心注冊(cè)自己為消費(fèi)者。

    @LoadBalanced表明開啟負(fù)載均衡功能。
    @Bean注解聲明一個(gè)RestTemplate bean

  4. 建一個(gè)服務(wù)類

         @Service
     public class HelloService {
     
         @Autowired
         RestTemplate restTemplate;
     
         public String sayHello(String name) {
             return restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class);
         }
     }
    
  5. 建一個(gè)對(duì)應(yīng)的測(cè)試用例

     @RunWith(SpringRunner.class)
     @SpringBootTest(classes=ServicveConsumerApplication.class)
     public class HelloServiceTest {
     
         @Autowired
         HelloService helloService;
     
         @Test
         public void sayHello() throws Exception {
             for (int i = 0; i < 10; i++){
                 System.out.println(helloService.sayHello("yunsheng"));
             }
     
         }
     
     }
    

跑十次看一下結(jié)果。

    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762
    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762
    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762
    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762
    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762

很明顯看到了負(fù)載均衡的效果。

當(dāng)前我們的應(yīng)用架構(gòu)是:

4.png

feign

Feign是一個(gè)聲明試的web服務(wù)客戶端。可以讓你寫web service client更簡(jiǎn)單。Feign默認(rèn)集成了Ribbon。
還是使用上面的工程,知識(shí)需要加一個(gè)Feign的依賴。

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>
  1. 新建一個(gè)啟動(dòng)類

     @SpringBootApplication
     @EnableDiscoveryClient
     @EnableFeignClients
     public class FeignConsumerApplication {
     
         public static void main(String[] args) {
             SpringApplication.run(FeignConsumerApplication.class, args);
         }
     
     }
    

    新增一個(gè)@EnableFeignClients注解開啟Feign功能

  2. 新建一個(gè)feign服務(wù)類

     @FeignClient(value = "service-hi")
     public interface FeignConsumeService {
     
         @RequestMapping(value = "/hi",method = RequestMethod.GET)
         String sayHiFromClientOne(@RequestParam(value = "name") String name);
     }
    

這里的功能就是一個(gè)服務(wù)代理的接口,只是內(nèi)部默認(rèn)實(shí)現(xiàn)了負(fù)載均衡。
這里的requestMapping必須是服務(wù)提供者的RequestMapping保持一致。

  1. controller層對(duì)外暴露一個(gè)服務(wù)調(diào)用

     @RestController
     public class HiController {
         @Autowired
         FeignConsumeService feignConsumeService;
     
         @RequestMapping(value = "/feignHi", method = RequestMethod.GET)
         public String sayHi(@RequestParam(value = "name") String name){
             return feignConsumeService.sayHiFromFeign(name);
         }
     
     
     }
    

這里的requestMapping隨便寫。

  1. 啟動(dòng)。
5.png
可以看到消費(fèi)者已經(jīng)注冊(cè)。  
  1. 消費(fèi)
    因?yàn)槲覀冮_放的是rest服務(wù),所以直接瀏覽器測(cè)試。
    瀏覽器多次訪問
    http://localhost:8764/feignHi?name=yunsheng
    可以看到負(fù)載均衡的效果,間隔調(diào)用8762和8763的服務(wù)。

Hystrix斷路器

在微服務(wù)架構(gòu)中,各個(gè)服務(wù)模塊獨(dú)立部署。但是由于各種原因,并不能保證服務(wù)100%成功。如果某個(gè)服務(wù)發(fā)送異常,產(chǎn)生線程阻塞。測(cè)試有大量請(qǐng)求進(jìn)入,會(huì)導(dǎo)致servlet線程被耗盡。由于服務(wù)之間的依賴,導(dǎo)致耽擱服務(wù)的異常被傳播擴(kuò)大,產(chǎn)生災(zāi)難性后果。為了避免這種情況,業(yè)界采用斷路器模式,當(dāng)服務(wù)不可用情況達(dá)到一定閾值后,斷路器打開,避免故障傳播。

  1. 添加依賴
    基于service-consumer工程添加依賴

     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-hystrix</artifactId>
     </dependency>
    
  2. 改造啟動(dòng)類

     @SpringBootApplication
     @EnableDiscoveryClient
     @EnableHystrix
     public class ServicveConsumerApplication {
     
         public static void main(String[] args) {
             SpringApplication.run(ServicveConsumerApplication.class, args);
         }
     
         @Bean
         @LoadBalanced
         RestTemplate restTemplate() {
             return new RestTemplate();
         }
     }
    

    添加@EnableHystrix注解,開啟斷路器功能

  3. 改造HelloService

     @Service
     public class HelloService {
     
         @Autowired
         RestTemplate restTemplate;
     
         @HystrixCommand(fallbackMethod = "sayErr")
         public String sayHello(String name) {
             return restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class);
         }
     
         public String sayErr(String name) {
             return "hi,"+name+",sorry,error!";
         }
     }
    

給之前的sayHello方法添加@HystrixCommand注解,并指定失敗時(shí)調(diào)用的方法。

  1. 測(cè)試
    先將8762和8763兩個(gè)服務(wù)提供者關(guān)掉。
    先將 @HystrixCommand(fallbackMethod = "sayErr")注釋掉,關(guān)閉斷路器。
    為了方便看出效果。也給ribbon方式新建一個(gè)rest的controller。

     @RestController
     public class HiController {
         @Autowired
         HelloService helloService;
     
         @RequestMapping(value = "/ribbonHi", method = RequestMethod.GET)
         public String sayHi(@RequestParam(value = "name") String name) {
             return helloService.sayHello("yys");
         }
     
     
     }
    

瀏覽器訪問http://localhost:8764/ribbonHi?name=yys
需要等到響應(yīng)超時(shí)才能得到錯(cuò)誤頁面。
但是開啟了斷路器之后,
再次嘗試,可以看到很快輸出hi,yys,sorry,error!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,786評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,656評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,697評(píng)論 0 379
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,098評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,855評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,254評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,322評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,473評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,014評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,833評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,016評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,568評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,273評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,680評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,946評(píng)論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,730評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,006評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容