當(dāng)javassist遇見Spring boot

最近在開發(fā)自己的開源項(xiàng)目REACTIVE DUBBO過程中,需要修改Dubbo的一個(gè)工具類RpcUtils桩盲,通過選型決定用字節(jié)碼工具javassist對一個(gè)靜態(tài)方法進(jìn)行魔改。在編碼階段很順利實(shí)現(xiàn)了我想要的效果席吴,但是當(dāng)打包進(jìn)行驗(yàn)證時(shí)問題出現(xiàn)了。

問題分析

首先來到事發(fā)地點(diǎn)

try {
            ClassPool classPool = ClassPool.getDefault();
            CtClass ctClass = classPool.get(RPCUTILS_CLASS_NAME);
            CtMethod ctMethod = ctClass.getDeclaredMethod("getReturnTypes");
            //rename from `getReturnTypes` to `getReturnTypes0`
            ctClass.removeMethod(ctMethod);
            ctMethod.setName("getReturnTypes0");
            ctClass.addMethod(ctMethod);
            //add new `getReturnTypes` method according to RpcUtilsCracker.getReturnTypes
            CtClass ctClass1 = classPool.get(RpcUtilsCracker.class.getName());
            ctMethod = new CtMethod(ctClass1.getDeclaredMethod("getReturnTypes"),ctClass,null);
            ctClass.addMethod(ctMethod);
            ctClass.toClass();
        } catch (NotFoundException|CannotCompileException e) {
            logger.warn("crack RpcUtils failed",e);
        }

這段代碼的用途是將RpcUtilsgetReturnTypes方法重命名捞蛋,并增加自定義的方法孝冒。在開發(fā)階段運(yùn)行正常,然而在使用spring-boot:run運(yùn)行(或者用Uber jar運(yùn)行)時(shí)會(huì)報(bào)如下錯(cuò)誤:

javassist.NotFoundException: com.alibaba.dubbo.rpc.support.RpcUtils
    at javassist.ClassPool.get(ClassPool.java:452) ~[javassist-3.20.0-GA.jar:na]
    at com.github.cherrythefatbunny.reactive.dubbo.extensions.rpc.support.RpcUtilsCracker.hack(RpcUtilsCracker.java:28) ~[reactive-dubbo-extensions-1.0.2-SNAPSHOT.jar:na]
    at com.github.cherrythefatbunny.reactive.dubbo.boot.ReactiveApplicationContextInitializer.initialize(ReactiveApplicationContextInitializer.java:14) [reactive-dubbo-starter-1.0.2-SNAPSHOT.jar:na]
    at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:649) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:373) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at com.github.cherrythefatbunny.demo.consumer.ConsumerApplication.main(ConsumerApplication.java:12) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:558) [spring-boot-maven-plugin-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]

報(bào)錯(cuò)語句為classPool.get(RPCUTILS_CLASS_NAME)拟杉,由于這段代碼是要修改存量的類庄涡,javassist需要首先讀class文件。debug發(fā)現(xiàn)執(zhí)行到Object.class.getResource(jarname)時(shí)搬设,用IDE啟動(dòng)能返回該類的URL穴店,而Spring boot啟動(dòng)則返回空。

繼續(xù)跟斷點(diǎn)發(fā)現(xiàn)拿穴,最終是使用類加載器Launcher$AppClassLoader完成加載操作泣洞,這樣問題定位是出在ClassLoader身上,要想解決這個(gè)問題首先要從JVM類加載機(jī)制以及Spring boot的啟動(dòng)原理說起默色。

成功獲取Class:


成功獲取Class

未能獲取Class:


未能獲取Class

JVM類加載

類加載器

類加載器用來動(dòng)態(tài)加載Java類到Java虛擬機(jī)的內(nèi)存空間中球凰,分為Bootstrap、Extension和System以及User-Defined。其中Bootstrap負(fù)責(zé)加載<JAVA_HOME>/lib路徑下的核心類庫或-Xbootclasspath參數(shù)指定的路徑下的類呕诉;Extension負(fù)責(zé)加載<JAVA_HOME>/lib/ext目錄下或者由系統(tǒng)變量-Djava.ext.dir指定位路徑中的類缘厢;System負(fù)責(zé)加載ClassPath下的類。

雙親委派模型

除了Bootstrap甩挫,每個(gè)類加載器都有父類加載器贴硫,當(dāng)類加載器接收到類加載請求時(shí)它會(huì)先將請求發(fā)給父類加載器處理,如果加載不成功才自己嘗試加載伊者。所以通過子類加載器可以找到父類加載器加載的類英遭,反之不可以

JVM ClassLoader

Spring boot啟動(dòng)原理導(dǎo)致的差異

通過IDE(IntelliJ)啟動(dòng)

開發(fā)階段可以通過項(xiàng)目的主函數(shù)啟動(dòng)Spring boot删壮,通過啟動(dòng)命令我們發(fā)現(xiàn)IDE會(huì)自動(dòng)將依賴加入classpath贪绘,這樣的啟動(dòng)方式和普通Java項(xiàng)目并無二致,javassist也能順利找到類RpcUtils央碟。

/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/bin/java 
-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:59051,suspend=y,server=n 
-Dvisualvm.id=202724856185364 -XX:TieredStopAtLevel=1 -noverify 
-Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote 
-Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true 
-javaagent:/Users/cherry/Library/Caches/IntelliJIdea2018.3/captureAgent/debugger-agent.jar -Dfile.encoding=UTF-8 
-classpath "/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/charsets.jar:
            ...
            /Users/cherry/IdeaProjects/reactive-dubbo/demo/consumer/target/classes:
            /Users/cherry/IdeaProjects/reactive-dubbo/demo/facade/target/classes:
            ...
            /Users/cherry/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.2.RELEASE/spring-boot-starter-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/boot/spring-boot/2.1.2.RELEASE/spring-boot-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.2.RELEASE/spring-boot-autoconfigure-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.1.2.RELEASE/spring-boot-starter-logging-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/cherry/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/cherry/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.11.1/log4j-to-slf4j-2.11.1.jar:/Users/cherry/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.1/log4j-api-2.11.1.jar:/Users/cherry/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:/Users/cherry/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/Users/cherry/.m2/repository/org/springframework/spring-core/5.1.4.RELEASE/spring-core-5.1.4.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/spring-jcl/5.1.4.RELEASE/spring-jcl-5.1.4.RELEASE.jar:/Users/cherry/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:/Users/cherry/.m2/repository/com/alibaba/spring/spring-context-support/1.0.2/spring-context-support-1.0.2.jar:/Users/cherry/.m2/repository/com/alibaba/boot/dubbo-spring-boot-starter/0.2.1.RELEASE/dubbo-spring-boot-starter-0.2.1.RELEASE.jar:/Users/cherry/.m2/repository/com/alibaba/boot/dubbo-spring-boot-autoconfigure/0.2.1.RELEASE/dubbo-spring-boot-autoconfigure-0.2.1.RELEASE.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo/2.6.5/dubbo-2.6.5.jar:/Users/cherry/.m2/repository/org/springframework/spring-context/5.1.4.RELEASE/spring-context-5.1.4.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/spring-aop/5.1.4.RELEASE/spring-aop-5.1.4.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/spring-beans/5.1.4.RELEASE/spring-beans-5.1.4.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/spring-expression/5.1.4.RELEASE/spring-expression-5.1.4.RELEASE.jar:/Users/cherry/.m2/repository/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar:/Users/cherry/.m2/repository/org/jboss/netty/netty/3.2.5.Final/netty-3.2.5.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-all/4.1.31.Final/netty-all-4.1.31.Final.jar:/Users/cherry/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8.jar:/Users/cherry/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar:/Users/cherry/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8.jar:/Users/cherry/.m2/repository/org/springframework/boot/spring-boot-starter-webflux/2.1.2.RELEASE/spring-boot-starter-webflux-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.1.2.RELEASE/spring-boot-starter-json-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.8/jackson-datatype-jdk8-2.9.8.jar:/Users/cherry/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.8/jackson-datatype-jsr310-2.9.8.jar:/Users/cherry/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.8/jackson-module-parameter-names-2.9.8.jar:/Users/cherry/.m2/repository/org/springframework/boot/spring-boot-starter-reactor-netty/2.1.2.RELEASE/spring-boot-starter-reactor-netty-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/io/projectreactor/netty/reactor-netty/0.8.4.RELEASE/reactor-netty-0.8.4.RELEASE.jar:/Users/cherry/.m2/repository/io/netty/netty-codec-http/4.1.31.Final/netty-codec-http-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-codec/4.1.31.Final/netty-codec-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-codec-http2/4.1.31.Final/netty-codec-http2-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-handler/4.1.31.Final/netty-handler-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-buffer/4.1.31.Final/netty-buffer-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-transport/4.1.31.Final/netty-transport-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-resolver/4.1.31.Final/netty-resolver-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-handler-proxy/4.1.31.Final/netty-handler-proxy-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-codec-socks/4.1.31.Final/netty-codec-socks-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-transport-native-epoll/4.1.31.Final/netty-transport-native-epoll-4.1.31.Final-linux-x86_64.jar:/Users/cherry/.m2/repository/io/netty/netty-common/4.1.31.Final/netty-common-4.1.31.Final.jar:/Users/cherry/.m2/repository/io/netty/netty-transport-native-unix-common/4.1.31.Final/netty-transport-native-unix-common-4.1.31.Final.jar:/Users/cherry/.m2/repository/org/hibernate/validator/hibernate-validator/6.0.14.Final/hibernate-validator-6.0.14.Final.jar:/Users/cherry/.m2/repository/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar:/Users/cherry/.m2/repository/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar:/Users/cherry/.m2/repository/com/fasterxml/classmate/1.4.0/classmate-1.4.0.jar:/Users/cherry/.m2/repository/org/springframework/spring-web/5.1.4.RELEASE/spring-web-5.1.4.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/spring-webflux/5.1.4.RELEASE/spring-webflux-5.1.4.RELEASE.jar:/Users/cherry/.m2/repository/org/synchronoss/cloud/nio-multipart-parser/1.1.0/nio-multipart-parser-1.1.0.jar:/Users/cherry/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/Users/cherry/.m2/repository/org/synchronoss/cloud/nio-stream-storage/1.1.3/nio-stream-storage-1.1.3.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo-registry-zookeeper/2.6.5/dubbo-registry-zookeeper-2.6.5.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo-registry-api/2.6.5/dubbo-registry-api-2.6.5.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo-cluster/2.6.5/dubbo-cluster-2.6.5.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo-rpc-api/2.6.5/dubbo-rpc-api-2.6.5.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo-serialization-api/2.6.5/dubbo-serialization-api-2.6.5.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo-container-api/2.6.5/dubbo-container-api-2.6.5.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo-remoting-zookeeper/2.6.5/dubbo-remoting-zookeeper-2.6.5.jar:/Users/cherry/.m2/repository/com/alibaba/dubbo-common/2.6.5/dubbo-common-2.6.5.jar:/Users/cherry/.m2/repository/commons-logging/commons-logging/1.2/commons-logging-1.2.jar:/Users/cherry/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar:/Users/cherry/.m2/repository/com/alibaba/hessian-lite/3.2.4/hessian-lite-3.2.4.jar:/Users/cherry/.m2/repository/com/alibaba/fastjson/1.2.46/fastjson-1.2.46.jar:/Users/cherry/.m2/repository/com/esotericsoftware/kryo/4.0.1/kryo-4.0.1.jar:/Users/cherry/.m2/repository/com/esotericsoftware/reflectasm/1.11.3/reflectasm-1.11.3.jar:/Users/cherry/.m2/repository/com/esotericsoftware/minlog/1.3.0/minlog-1.3.0.jar:/Users/cherry/.m2/repository/de/javakaffee/kryo-serializers/0.42/kryo-serializers-0.42.jar:/Users/cherry/.m2/repository/de/ruedigermoeller/fst/2.48-jdk-6/fst-2.48-jdk-6.jar:/Users/cherry/.m2/repository/com/cedarsoftware/java-util/1.9.0/java-util-1.9.0.jar:/Users/cherry/.m2/repository/com/cedarsoftware/json-io/2.5.1/json-io-2.5.1.jar:/Users/cherry/.m2/repository/org/apache/zookeeper/zookeeper/3.4.9/zookeeper-3.4.9.jar:/Users/cherry/.m2/repository/org/slf4j/slf4j-log4j12/1.7.25/slf4j-log4j12-1.7.25.jar:/Users/cherry/.m2/repository/jline/jline/0.9.94/jline-0.9.94.jar:/Users/cherry/.m2/repository/io/netty/netty/3.10.5.Final/netty-3.10.5.Final.jar:/Users/cherry/.m2/repository/com/101tec/zkclient/0.2/zkclient-0.2.jar:/Users/cherry/.m2/repository/org/apache/curator/curator-framework/2.12.0/curator-framework-2.12.0.jar:/Users/cherry/.m2/repository/org/apache/curator/curator-client/2.12.0/curator-client-2.12.0.jar:/Users/cherry/.m2/repository/com/google/guava/guava/16.0.1/guava-16.0.1.jar:/Users/cherry/IdeaProjects/reactive-dubbo/reactive-dubbo-starter/target/classes:/Users/cherry/IdeaProjects/reactive-dubbo/reactive-dubbo-extensions/target/classes:/Users/cherry/.m2/repository/org/springframework/boot/spring-boot-autoconfigure-processor/2.1.2.RELEASE/spring-boot-autoconfigure-processor-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/org/springframework/boot/spring-boot-configuration-processor/2.1.2.RELEASE/spring-boot-configuration-processor-2.1.2.RELEASE.jar:/Users/cherry/.m2/repository/io/projectreactor/reactor-core/3.2.5.RELEASE/reactor-core-3.2.5.RELEASE.jar:/Users/cherry/.m2/repository/org/reactivestreams/reactive-streams/1.0.2/reactive-streams-1.0.2.jar:/Users/cherry/.m2/repository/org/projectlombok/lombok/1.18.4/lombok-1.18.4.jar:/Users/cherry/.m2/repository/org/ow2/asm/asm/5.0.4/asm-5.0.4.jar:/Users/cherry/.m2/repository/org/objenesis/objenesis/2.6/objenesis-2.6.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar" com.github.cherrythefatbunny.demo.consumer.ConsumerApplication

通過jar啟動(dòng)

Spring boot定義了一套打包標(biāo)準(zhǔn)税灌,將依賴的jar都打包成一個(gè)Uber jar,啟動(dòng)類變成了Spring boot打包進(jìn)去的JarLauncher亿虽,JarLauncher會(huì)通過自定義的LaunchedURLClassLoader加載Uber jar內(nèi)部的lib jar內(nèi)部的class??,
由于所尋找的類不在classpath內(nèi)菱涤,因此通過之前的Launcher$AppClassLoader是無法找到的,這正是報(bào)錯(cuò)的原因洛勉。

── BOOT-INF
│   ├── classes
│   │   ├── application.properties
│   │   └── com
│   │       └── github
│   │           └── cherrythefatbunny
│   │               └── demo
│   │                   └── consumer
│   │                       ├── ConsumerApplication.class
│   │                       └── PersonController.class
│   └── lib
│       ├── asm-5.0.4.jar
│       ...
│       ├── zkclient-0.2.jar
│       └── zookeeper-3.4.9.jar
├── META-INF
│   ├── MANIFEST.MF
│   └── maven
│       └── com.github.cherrythefatbunny.demo
│           └── consumer
│               ├── pom.properties
│               └── pom.xml
└── org
    └── springframework
        └── boot
            └── loader
                ├── ExecutableArchiveLauncher.class
                ├── JarLauncher.class
                ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
                ├── LaunchedURLClassLoader.class
                ├── Launcher.class
                ...

解決問題

找到了問題的根源是javassist默認(rèn)使用Object類的Launcher$AppClassLoader粘秆,而所依賴的jar都是通過Spring boot的LaunchedURLClassLoader加載的。根據(jù)JVM的雙親委派模型可知收毫,使用Launcher$AppClassLoader是無法查找子類加載器LaunchedURLClassLoader所加載類的攻走。幸好javassist為我們留下了擴(kuò)展的方法,classPool.appendClassPath(new LoaderClassPath(RpcUtilsCracker.class.getClassLoader()));,通過向ClassPool添加一個(gè)能訪問到類RpcUtils的ClassLoader就可以解決問題此再。這里我選了代碼所在的類RpcUtilsCracker昔搂,由于我開發(fā)的是一個(gè)Spring boot starter,因此該類會(huì)被LaunchedURLClassLoader所加載输拇。經(jīng)過編譯打包發(fā)現(xiàn)摘符,報(bào)錯(cuò)不再出現(xiàn)??。

總結(jié)

Spring boot是Spring生態(tài)重要的組成策吠,給程序員帶來了極大便利逛裤,但不代表這個(gè)項(xiàng)目問題就少,而且底層框架不出問題則已猴抹,一有問題就讓你懷疑人生带族。之前就曾經(jīng)遇到過使用Spring boot熱部署工具,導(dǎo)致類型判定出現(xiàn)問題洽糟。

最近在學(xué)習(xí)響應(yīng)式編程炉菲,最開始有一定門檻堕战,一旦邁過去就欲罷不能。趁熱寫了一個(gè)小項(xiàng)目REACTIVE DUBBO拍霜,Make your Dubbo reactive嘱丢!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市祠饺,隨后出現(xiàn)的幾起案子越驻,更是在濱河造成了極大的恐慌,老刑警劉巖道偷,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缀旁,死亡現(xiàn)場離奇詭異,居然都是意外死亡勺鸦,警方通過查閱死者的電腦和手機(jī)并巍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來换途,“玉大人懊渡,你說我怎么就攤上這事【猓” “怎么了剃执?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長懈息。 經(jīng)常有香客問我肾档,道長,這世上最難降的妖魔是什么辫继? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任怒见,我火速辦了婚禮,結(jié)果婚禮上姑宽,老公的妹妹穿的比我還像新娘速种。我一直安慰自己,他們只是感情好低千,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著馏颂,像睡著了一般示血。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上救拉,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天难审,我揣著相機(jī)與錄音,去河邊找鬼亿絮。 笑死告喊,一個(gè)胖子當(dāng)著我的面吹牛麸拄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播黔姜,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼拢切,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了秆吵?” 一聲冷哼從身側(cè)響起淮椰,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纳寂,沒想到半個(gè)月后主穗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡毙芜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年忽媒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腋粥。...
    茶點(diǎn)故事閱讀 40,567評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晦雨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灯抛,到底是詐尸還是另有隱情金赦,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布对嚼,位于F島的核電站夹抗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏纵竖。R本人自食惡果不足惜漠烧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望靡砌。 院中可真熱鬧已脓,春花似錦、人聲如沸通殃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽画舌。三九已至堕担,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間曲聂,已是汗流浹背霹购。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朋腋,地道東北人齐疙。 一個(gè)月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓膜楷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贞奋。 傳聞我的和親對象是個(gè)殘疾皇子赌厅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評論 2 359

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