这可能是最手把手的dubbo框架入门

Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC实现服务的输出和输入功能,可以和Spring框架无缝集成。
Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
对于Dubbo框架中,首先要了解其中涉及的三个基本的概念:provider(服务提供方),consumer(服务消费方)和注册中心。接下来,本文从这几个角色的角度,分别实现一个小的demo,以便尽快对于dubbo框架有一个简单的入门。

0、准备

这里们采用的IDE是macOS下的IDEA。我们新健一个名为DubboDemoProj的空Java工程,只选JDK就行,别的都不用选。


new empty project

我们将在这个工程中,新建各个Module来实现Dubbo框架中的各个角色。

1、接口依赖模块dubbo-api

dubbo-api模块提供统一的接口,最终会打为jar包,供consumer和provider引用。
这里dubbo-api模块新建的时候,要选Maven,但是不要勾选任何archetype,只需要建一个空的Maven项目就行。建好之后,结构如下图。

dubbo-api structure

dubbo-api/pom.xml是Maven的配置文件。其中,定义了该Module依赖了dubbo框架,同时为了避免Dubbo自带的Spring框架过低,我们排除掉了dubbo自带的spring框架,并显示指定了spring依赖的版本。如下。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.spacecat.dubbo</groupId>
    <artifactId>dubbo-api</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring</artifactId>
                </exclusion>
            </exclusions>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.2.5.RELEASE</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

user-references.xml文件是该Module的classpath路径下提供了一个xml配置,该配置文件其实就是dubbo消费者的相关配置,后边消费者项目引入api之后可以直接使用该文件。内容如下。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://code.alibabatech.com/schema/dubbo
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 引用服务配置 -->
    <dubbo:reference id="userService" interface="com.dubbo.api.UserService" cluster="failfast" check="false"/>
</beans>

UserService.java是一个接口,他定义了统一的接口让provider和consumer来引用,内容如下。

package com.dubbo.api;

/**
 * Created by chengxia on 2019/5/3.
 */
public interface UserService {
    String sayHi(String name);
}

编辑完上述源码文件之后,执行mvn install命令,将这个module装到mvn的本地仓库。这样,后面的项目就能够通过这个module的坐标在Maven的pom文件中,引用到这个模块。

$ mvn install
[INFO] Scanning for projects...
[INFO] 
[INFO] --------------------< com.spacecat.dubbo:dubbo-api >--------------------
[INFO] Building dubbo-api 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ dubbo-api ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ dubbo-api ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ dubbo-api ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ dubbo-api ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ dubbo-api ---
[INFO] No tests to run.
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ dubbo-api ---
[INFO] Building jar: /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/target/dubbo-api-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ dubbo-api ---
[INFO] Installing /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/target/dubbo-api-1.0-SNAPSHOT.jar to /Users/chengxia/Developer/Java/tools/apache-maven-3.6.0/repository/com/spacecat/dubbo/dubbo-api/1.0-SNAPSHOT/dubbo-api-1.0-SNAPSHOT.jar
[INFO] Installing /Users/chengxia/Developer/Java/DubboDemoProj/dubbo-api/pom.xml to /Users/chengxia/Developer/Java/tools/apache-maven-3.6.0/repository/com/spacecat/dubbo/dubbo-api/1.0-SNAPSHOT/dubbo-api-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.537 s
[INFO] Finished at: 2019-05-05T00:45:01+08:00
[INFO] ------------------------------------------------------------------------
ChengdeMacBook-Pro:dubbo-api chengxia$ 

2、服务提供方模块dubbo-provider

同样是一个在DubboDemoProj中的空Maven模块,建好之后,结构如下图。


dubbo-provider structure

pom.xml文件,其中,针对上面dubbo-api模块的依赖,具体如下。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.spacecat.dubbo</groupId>
    <artifactId>dubbo-provider</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.spacecat.dubbo</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
    </dependencies>

</project>

UserServiceImpl.java是服务的实现类,如下。

package com.dubbo.provider;

import com.dubbo.api.UserService;

/**
 * Created by chengxia on 2019/5/3.
 */
public class UserServiceImpl implements UserService {
    public String sayHi(String s) {
        return "hello " + s + "!";
    }
}

com.dubbo.provider.Main是启动dubbo服务的,内容如下。

package com.dubbo.provider;

/**
 * Created by chengxia on 2019/5/3.
 */
public class Main {
    public static void main(String[] args) {
        com.alibaba.dubbo.container.Main.main(args);
    }
}

这个类调是dubbo框架提供的方法来启动dubbo服务。dubbo会在启动服务时,会读取classpath下一个名为dubbo.properties文件的属性配置。这里我们只要按照dubbo的规则配置相关参数即可,如下:
dubbo.properties

dubbo.container=spring
#set dubbo Sping load setting xmls
dubbo.spring.config=classpath:dubbo-provider.xml
dubbo.protocol.name=dubbo
dubbo.protocol.port=28511

dubbo.container指定了dubbo的容器使用spring,dubbo内部有四种容器实现,SpringContainer是其中一种,也是默认的容器。dubbo.spring.config指定了dubbo在启动服务时加载的spring配置文件。dubbo.protocol.name和dubbo.protocol.port分别指定使用的协议名和端口。


dubbo source example

上图是Spring源码的截图。SpringContainer类中定义了两个常量,SPRING_CONFIG和DEFAULT_SPRING_CONFIG,大概读一下代码就可以知道,start方法在执行时,会读取dubbo.spring.config属性值,该值指定的就是spring的配置文件,如果没读到,则使用默认的配置。默认配置为classpath*;META-INF/spring/*.xml,意思是读取classpath下META-INF文件夹下的spring文件夹中的所有xml文件。所以,我们也可以不配置dubbo.spring.config,但是要遵循dubbo默认的读取路径,将spring配置文件放置在META-INF/spring文件夹下。
dubbo-provider.xml是一个spring配置文件,只不过引入了dubbo相关的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://code.alibabatech.com/schema/dubbo
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <dubbo:application name="dubbo-provider"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:provider cluster="failfast"/>
    <bean id="userService" class="com.dubbo.provider.UserServiceImpl"/>
    <dubbo:service interface="com.dubbo.api.UserService" ref="userService"/>
</beans>

其中:

  • <dubbo:application>指定了程序名称,我们可以在dubbo管理后台中通过该名称更清晰的区分服务
  • <dubbo:registry>指定了注册中心的地址,这里用的是本地的zookeeper。
  • <dubbo:provider>指定了集群容错模式,此处为快速失败
  • <bean>普通的spring依赖注入
  • <dubbo:service>服务导出,引用<bean>标签注入的类

3、注册中心

这里的注册中心,我们使用的是zookeeper。

3.1 zookeeper安装

$ brew info zookeeper
zookeeper: stable 3.4.13 (bottled), HEAD
Centralized server for distributed coordination of services
https://zookeeper.apache.org/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/zookeeper.rb
==> Options
--HEAD
    Install HEAD version
==> Caveats
To have launchd start zookeeper now and restart at login:
  brew services start zookeeper
Or, if you don't want/need a background service you can just run:
  zkServer start
==> Analytics
install: 5,018 (30 days), 14,429 (90 days), 58,577 (365 days)
install_on_request: 1,733 (30 days), 4,463 (90 days), 19,783 (365 days)
build_error: 0 (30 days)
$ 

执行brew安装命令:

$ brew install zookeeper
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).

... ...

==> Deleted Formulae
safe

==> Downloading https://homebrew.bintray.com/bottles/zookeeper-3.4.13.mojave.bottle.tar.gz
==> Downloading from https://akamai.bintray.com/d1/d1e4e7738cd147dceb3d91b32480c20ac5da27d129905f336ba51c0c01b8a476?__gda__=exp=1556685597~hmac=2a06d1cd6581464fdc9510af3179137ee9754a2d28f1fe423eafaebf5fb6aec9&re
######################################################################## 100.0%
==> Pouring zookeeper-3.4.13.mojave.bottle.tar.gz
==> Caveats
To have launchd start zookeeper now and restart at login:
  brew services start zookeeper
Or, if you don't want/need a background service you can just run:
  zkServer start
==> Summary
🍺  /usr/local/Cellar/zookeeper/3.4.13: 244 files, 33.4MB
==> `brew cleanup` has not been run in 30 days, running now...
Removing: /Users/chengxia/Library/Caches/Homebrew/fontconfig--2.13.1.mojave.bottle.tar.gz... (1.2MB)
Removing: /Users/chengxia/Library/Caches/Homebrew/freetype--2.9.1.mojave.bottle.tar.gz... (874.5KB)
Removing: /Users/chengxia/Library/Caches/Homebrew/gd--2.2.5.mojave.bottle.tar.gz... (290KB)
Removing: /Users/chengxia/Library/Caches/Homebrew/jpeg--9c.mojave.bottle.tar.gz... (300.8KB)
Removing: /Users/chengxia/Library/Caches/Homebrew/libtool--2.4.6_1.mojave.bottle.tar.gz... (1003.4KB)
Removing: /Users/chengxia/Library/Logs/Homebrew/tree... (64B)
$ 

安装后,在/usr/local/etc/zookeeper/目录下,已经有了缺省的配置文件。查看zookeeper配置文件:

$ ls /usr/local/etc/zookeeper
defaults        log4j.properties    zoo.cfg         zoo_sample.cfg
$ 

缺省配置/usr/local/etc/zookeeper/zoo.cfg 内容如下:

$ cat /usr/local/etc/zookeeper/zoo.cfg 
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=/usr/local/var/run/zookeeper/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the 
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
$ 

3.2 zookeeper启动

启动zookeeper:

$ zkServer
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Usage: ./zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}
ChengdeMacBook-Pro:~ chengxia$ zkServer status
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Error contacting service. It is probably not running.
$ zkServer start
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Starting zookeeper ... STARTED
$ zkServer status
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Mode: standalone
$ 

3.3 zookeeper简单操作

查看zookeeper的运行状态:

$ zkCli
Connecting to localhost:2181
Welcome to ZooKeeper!
JLine support is enabled

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] ls
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 2] ls /zookeeper
[quota]
[zk: localhost:2181(CONNECTED) 3] ls /zookeeper/quota 
[]
[zk: localhost:2181(CONNECTED) 4] quit
Quitting...
$ 

停止运行zookeeper:

$ zkServer stop
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Stopping zookeeper ... STOPPED
$ 

4、服务消费方

到这里,我们在本地启动zookeeper,然后,在IDEA中运行上面的com.dubbo.provider.Main,我们就将上面的服务注册到了本机的注册中心(zookeeper)。接下来,可以调用这个服务。

4.1 写一个简单的Spring项目来当做服务消费方

项目结构如下图。


spring-consumer structure

dubbo-consumer/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.spacecat.dubbo</groupId>
    <artifactId>dubbo-consumer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring Core -->
        <!-- http://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <!-- Spring Context -->
        <!-- http://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.spacecat.dubbo</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
    </dependencies>

</project>

这个Module中,依赖了dubbo-api。
dubbo-consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <dubbo:application name="dubbo-consumer"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:consumer check="false"/>

    <!-- 导入dubbo配置,dubbo-api模块打包后自带的配置文件 -->
    <import resource="classpath*:user-references.xml"/>
</beans>

这个文件中,直接引用了dubbo-api模块打包后自带的配置文件user-references.xml
com.dubbo.consumer.UserServiceCaller

package com.dubbo.consumer;

import com.dubbo.api.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by chengxia on 2019/5/5.
 */
public class UserServiceCaller {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("dubbo-consumer.xml");
        UserService service = (UserService) context.getBean("userService");
        System.out.print("Got service bean:");
        System.out.println(service);
        System.out.println("RPC call output:");
        System.out.println(service.sayHi("Kobe"));
    }
}

该文件完成了对服务的调用,可见dubbo框架已经把服务注入到一个本地可以直接调用的bean中了。直接调用bean的方法即可完成对于服务的远程调用(其实,已经和调本地一样了)。
启动zookeeper,运行前面的dubbo-provider模块中的启动类,然后再运行com.dubbo.consumer.UserServiceCaller,可以得到如下输出。

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Got service bean:com.alibaba.dubbo.common.bytecode.proxy0@49dc7102
RPC call output:
hello Kobe!

Process finished with exit code 0

4.2 通过命令行调用服务

通过命令行调用服务适用于对dubbo服务做个简单的测试的情况。可以直接在命令行通过telnet的方式来查看和调用dubbo服务。
新版本的MacOS默认没有telnet,可以通过如下步骤安装。

4.2.1 MacOS安装telnet

$ telnet
-bash: telnet: command not found
$ brew install telnet
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
==> New Formulae
pipx
==> Updated Formulae
allureofthestars     bluepill             dovecot              glib-networking      gupnp                mercurial            php@7.2              pulumi               qt                   translate-shell
bettercap            bzt                  faas-cli             gmic                 hugo                 pdftoipe             poppler              pumba                taskell
bit                  diff-pdf             ghq                  gssdp                imagemagick@6        php                  prototool            pushpin              tmux
==> Deleted Formulae
node@6

==> Downloading https://homebrew.bintray.com/bottles/telnet-60.mojave.bottle.tar.gz
######################################################################## 100.0%
==> Pouring telnet-60.mojave.bottle.tar.gz
🍺  /usr/local/Cellar/telnet/60: 4 files, 138.2KB
ChengdeMacBook-Pro:~ chengxia$ telnet
telnet> quit
$ 

4.2.2 通过telnet查看和调用dubbo服务。

方法如下示例,这里的端口就是前面dubbo-provider模块中dubbo.properties文件中配置的端口,这个端口应该就是服务提供方的端口。

$ telnet 127.0.0.1 28511
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
ls
com.dubbo.api.UserService
dubbo>invoke com.dubbo.api.UserService.sayHi("Kobe")
"hello Kobe!"
elapsed: 1 ms.
dubbo>

参考资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容