Jacoco覆蓋率使用總結(jié)

tags: Java

前陣子使用 Jacoco 進(jìn)行代碼覆蓋率測(cè)試吸耿,由于項(xiàng)目特殊遇到了不少坑祠锣,網(wǎng)上搜到的教程感覺也不夠全面,特此記錄咽安。
所用到的工具軟件的版本信息如下

  • Jacoco 版本:0.8.0
  • Eclemma 版本:3.0.0
  • Eclipse 版本:4.3
  • JDK 版本:1.8
  • ANT 版本:1.9

1. 工具介紹

JaCoCo伴网,即 Java Code Coverage,是一款開源的 Java 代碼覆蓋率統(tǒng)計(jì)工具妆棒。支持 Ant 澡腾、Maven、Gradle 等構(gòu)建工具糕珊,支持 Jenkins动分、Sonar 等持續(xù)集成工具,支持 Java Agent 技術(shù)遠(yuǎn)程監(jiān)控 Java 程序運(yùn)行情況红选,支持Eclipse澜公、IDEA等IDE,提供HTML喇肋,CSV 等格式的報(bào)表導(dǎo)出坟乾,輕量級(jí)實(shí)現(xiàn),對(duì)外部庫和系統(tǒng)資源的依賴性小蝶防,性能開銷小甚侣。

JaCoCo 支持從 JDK1.0 版本到 JDK1.8 版本 的 Java 類文件。但是间学,JaCoCo 工具所需的JRE 版本最小為 1.5饵筑。另外,1.6及以上版本的測(cè)試中的類文件必須包含有效的堆棧映射幀法瑟。

覆蓋率統(tǒng)計(jì)數(shù)據(jù)

2. 入門使用

本文將以 tcpserver 模式遠(yuǎn)程獲取應(yīng)用覆蓋率肉津,通過 Ant 腳本執(zhí)行相關(guān)命令,在 Eclipse 上查看源碼覆蓋率情況德谅。

2.1 配置部署

先從官網(wǎng)獲取 Jacoco 的壓縮包, 將其上傳到你要進(jìn)行覆蓋率檢測(cè)的應(yīng)用所在的服務(wù)器上。在解壓后的 lib 目錄下找到 jacocoagent 染苛,將其路徑添加到 JAVA_OPTS 環(huán)境變量中(如果項(xiàng)目中用到了 Tomcat,也可以直接將其添加到 CATALINA_OPTS 的環(huán)境變量中主到,JAVA_OPTS 只是更通用而已)茶行。

如果是 Windows 系統(tǒng),將以下內(nèi)容追加到 JAVA_OPTS 環(huán)境變量登钥。

-javaagent:D:\jacoco-0.7.9\lib\jacocoagent.jar=includes=*,address=10.1.231.168,port=6300,output=tcpserver,append=true;%JAVA_OPTS%

如果是 Linux 系統(tǒng)畔师,可以直接編輯 .bash_profile

export JACOCO="-javaagent:/$your_path/jacocoagent.jar=includes=com.grgbanking.*,output=tcpserver,address=11.111.1.11,port=6300,append=true"
export JAVA_OPTS="$JACOCO":"$JAVA_OPTS" 

其中常用選項(xiàng)的含義如下

  • javaagent: 指定 jacocoagent 的路徑
  • includes: 表示只對(duì)指定包下的類進(jìn)行覆蓋率注入分析,默認(rèn)為 *牧牢,示例中只分析 com.test 包的類看锉。
  • output: 表示覆蓋率的輸出方式。在 tcpserver 模式下塔鳍,Jacoco 會(huì)在客戶端執(zhí)行 dump 操作時(shí)將目前收集獲取到的覆蓋率數(shù)據(jù)統(tǒng)一寫到指定的ip和端口伯铣。在 file 模式下,Jacoco 只會(huì)在JVM 終止的時(shí)候才將收集到的覆蓋率數(shù)據(jù)寫入到指定的 exec 文件里去轮纫。注意腔寡,不管是任何模式,應(yīng)用運(yùn)行過程中的臨時(shí)覆蓋率數(shù)據(jù)都是保存在服務(wù)端的內(nèi)存中的掌唾,因此對(duì)于 tcpserver 模式來說放前,如果 JVM 不小心終止了,那么在這個(gè)覆蓋率統(tǒng)計(jì)周期內(nèi)的覆蓋率數(shù)據(jù)都會(huì)丟失糯彬。還有一個(gè) tcpclient 模式則是以客戶端的形式啟動(dòng)凭语,由于目前沒有這個(gè)使用場(chǎng)景,這里不過多討論撩扒。
  • address: 只限 tcpserver 與 tcpclient 使用叽粹,表示監(jiān)聽的應(yīng)用服務(wù)器IP地址或主機(jī)名∪匆ǎ可根據(jù)實(shí)際情況自由選擇虫几。
  • port: 只限 tcpserver 與 tcpclient 使用,表示監(jiān)聽的應(yīng)用服務(wù)器的端口號(hào)挽拔,一般用默認(rèn)6300即可辆脸。
  • append: 表示覆蓋率數(shù)據(jù)的追加方式,默認(rèn)為true螃诅》惹猓客戶端在執(zhí)行 dump 操作時(shí)状囱,如果該 exec 覆蓋率文件已存在,那么該輪的覆蓋率數(shù)據(jù)會(huì)直接在文本末尾進(jìn)行追加倘是,因此會(huì)導(dǎo)致覆蓋率數(shù)據(jù)文件越來越大亭枷。如果改為false,則客戶端執(zhí)行 dump 操作時(shí)會(huì)直接清空原覆蓋率文件的內(nèi)容搀崭,保證該覆蓋率文件只有該輪的覆蓋率數(shù)據(jù)叨粘。

修改好以后啟動(dòng) Java 應(yīng)用,讀取 JAVA_OPTS 環(huán)境變量的信息瘤睹,Jacoco 被加載進(jìn)升敲。檢查下6300端口如果已監(jiān)聽,說明服務(wù)端 Jacoco 啟動(dòng)成功轰传。

2.2 數(shù)據(jù)獲取

在正常運(yùn)行過程中驴党,服務(wù)器端的 Jacoco 只是將獲取的覆蓋率數(shù)據(jù)保存到內(nèi)存中,我們還需要在客戶端上進(jìn)行操作才能將覆蓋率數(shù)據(jù) dump 到客戶端获茬。

Jacoco 為我們提供了 Ant港庄、Maven、CLI 等多種方式進(jìn)行操作恕曲,其中 CLI 方式唯一的用途就是可以用來執(zhí)行 execinfo 命令鹏氧,這個(gè)命令是 Ant 與 Maven 所沒有的,它可以將 exec 簡(jiǎn)單轉(zhuǎn)成文本格式方便你查看每個(gè)類的覆蓋率百分比码俩。Maven 與 Ant 大同小異,由于項(xiàng)目中使用 Ant 進(jìn)行構(gòu)建歼捏,下文中將以 Ant 為例講解稿存。

在使用 Ant 腳本獲取覆蓋率之前,我們需要先去官網(wǎng)下載好 Ant瓣履,注意安裝過程中要手動(dòng)勾選 “添加到環(huán)境變量” 的相關(guān)選項(xiàng),省得以后要自己添加练俐。
安裝好以后打開 cmd 輸入ant -version袖迎,如果能顯示相關(guān)的版本信息例如 “ Apache Ant(TM) version 1.9.11 compiled on March 23 2018 ”,則說明 Ant 安裝成功腺晾。

雖然官方也提供了 Ant腳本燕锥,但較為簡(jiǎn)單,部分內(nèi)容沒有說明悯蝉,因此文末會(huì)附上我在項(xiàng)目中使用的完整腳本归形。

2.3 統(tǒng)計(jì)分析

對(duì)于不熟悉 Java 或者對(duì)項(xiàng)目目錄結(jié)構(gòu)不了解的朋友,往往會(huì)由于源碼和字節(jié)碼不匹配或者路徑錯(cuò)誤導(dǎo)致在結(jié)合源碼查看覆蓋率時(shí)反復(fù)折騰鼻由,跑半天不知道生成的 exec 到底有沒有統(tǒng)計(jì)到暇榴。這時(shí)候我們可以使用 CLI 中的 execinfo 命令厚棵,簡(jiǎn)單查看下 exec 文件中的覆蓋率是否為0。
java -jar D:\jacococli.jar execinfo E:\jacoco\igaps1008.exec

這種方式只能查看 exec 文件的概況蔼紧,要想結(jié)合源碼查看詳細(xì)的覆蓋率使用情況婆硬,我們還是需要花點(diǎn)時(shí)間,配置好源碼和字節(jié)碼奸例,這樣才能在 IDE 中查看源碼覆蓋率彬犯。

首先需要在 Eclipse 中安裝 Eclemma 插件,你可以使用 Eclipse 的 MarketPlace 在線安裝哩至,

在線安裝

也可以下載離線安裝包 eclemma-3.0.0.zip躏嚎,分別將里面的 features 和 plugins 文件夾里的 jar 包拷貝到 Eclipse 對(duì)應(yīng)的文件夾中,重啟 Eclipse 后如果有顯示覆蓋率圖標(biāo)或視圖就說明安裝成功了菩貌。

安裝后界面

接著下載項(xiàng)目源碼并將項(xiàng)目導(dǎo)入到 Eclipse 中

項(xiàng)目目錄結(jié)構(gòu)

注意導(dǎo)入前取消 Eclipse 中的自動(dòng)編譯(即 Project - build automatically )卢佣, 然后拷貝服務(wù)器上的字節(jié)碼文件到這個(gè)項(xiàng)目的編譯輸出文件夾中。例如這個(gè)項(xiàng)目的編譯輸出文件夾為根目錄下bin目錄箭阶,那么就把字節(jié)碼文件都拷貝到這個(gè)目錄下虚茶,到這里我們的項(xiàng)目就準(zhǔn)備好了。

在 Eclipse 控制臺(tái) Coverage 視圖窗口的空白位置仇参,右鍵--Import Session嘹叫,在 Coverage Session 窗口,選擇第三個(gè)代理模式诈乒,Agent address 填寫需要監(jiān)控覆蓋率的遠(yuǎn)程服務(wù)器地址罩扇。點(diǎn)擊下一步后,選擇需要查看覆蓋率的源碼怕磨,一般不需要勾選include binary libraries喂饥,再點(diǎn)擊Finish即可查看覆蓋率。

導(dǎo)入覆蓋率數(shù)據(jù)
tcpserver模式

3. 注意事項(xiàng)

  • 官方文檔才是王道
    強(qiáng)烈建議在使用 Jacoco 之前閱讀官方文檔肠鲫,雖然是英文员帮,但是內(nèi)容也很簡(jiǎn)單,花1個(gè)小時(shí)大概瀏覽下能對(duì) Jacoco 有個(gè)系統(tǒng)性的了解导饲。這里對(duì) Jacoco 的官方部分 FAQ 進(jìn)行了簡(jiǎn)單翻譯捞高,同時(shí)加入了部分自己在使用過程中遇到的坑。

  • 源代碼沒有覆蓋率高亮問題
    必須確保使用調(diào)試信息編譯類文件以包含行號(hào)渣锦,如果使用 Ant 編譯腳本硝岗,則需要檢查腳本中 javac 相關(guān)部分是否沒有設(shè)置 debug=true。
    源文件必須在報(bào)表生成時(shí)正確提供袋毙。即指定的源文件夾必須是定義Java包的文件夾的直接父級(jí)辈讶。

  • 覆蓋率統(tǒng)計(jì)偏差
    既然 Jacoco 是依據(jù) class 文件進(jìn)行覆蓋率的統(tǒng)計(jì),那么在用 EclEmma 合并會(huì)話數(shù)據(jù)時(shí)娄猫,應(yīng)該保證多個(gè)會(huì)話的所測(cè)試 class 文件字節(jié)碼內(nèi)容是相同的贱除,即多次測(cè)試過程中被測(cè)試 Java 類的源文件沒有被修改并且重新編譯過生闲。所以在 Eclipse 中,測(cè)試用例開始執(zhí)行執(zhí)行后月幌,應(yīng)該保證 Testee 源文件不被改動(dòng)碍讯。如果修改了被測(cè)試源文件并保存( Eclipse 會(huì)自動(dòng)重新編譯),請(qǐng)將之前的所有測(cè)試用例重新以 Coverage As 模式執(zhí)行一般扯躺,否則合并后的覆蓋率測(cè)試數(shù)據(jù)會(huì)有誤差捉兴。
    另外,由于 JaCoCo 分析統(tǒng)計(jì)的是編譯后的 class 文件中字節(jié)碼指令的執(zhí)行情況录语。例如某源文件中有一個(gè)靜態(tài)的方法 someMethod倍啥,但是在編譯時(shí) Javac 會(huì)自動(dòng)為我們的類生成一個(gè)構(gòu)造方法(本例中沒有提供非空的構(gòu)造方法),所以這個(gè)類同時(shí)有 someMethod 和一個(gè)構(gòu)造方法澎埠。由于在執(zhí)行靜態(tài)方法過程中沒有調(diào)用到構(gòu)造函數(shù)虽缕,所以會(huì)顯示覆蓋率不是100%

  • Android應(yīng)用使用覆蓋率
    由于Android不能通過JVM停止后自動(dòng)dump覆蓋率數(shù)據(jù),因此當(dāng)Android應(yīng)用進(jìn)程不存在或停止的時(shí)候蒲稳,覆蓋率數(shù)據(jù)不會(huì)生成氮趋。要想獲得Android應(yīng)用的覆蓋率,江耀,必須使用離線插樁模式進(jìn)行覆蓋率分析

  • 多源文件目錄
    Ant 腳本執(zhí)行起來很方便剩胁,但如果要執(zhí)行 report 命令則需要注意,如果該應(yīng)用編譯后的class 或 jar 分別在幾個(gè)不同的目錄下祥国,那么就需要分別在 Ant 腳本中指定 group昵观,同時(shí)每個(gè) group 也都要指定源文件 sourcefiles 以及 編譯后的類文件 classfiles。同樣的舌稀,如果
    項(xiàng)目的源碼存放目錄也沒有統(tǒng)一的入口啊犬,那也需要在一個(gè) sourcefiles 中指定多個(gè) fileset,就如本腳本中分別指定了<fileset dir="${JacocoClassPath}/lib/core"/><fileset dir="${JacocoClassPath}/project"/> 這2個(gè) classfiles 一樣扩借。

  • Eclipse中導(dǎo)入覆蓋率數(shù)據(jù)時(shí)出錯(cuò)
    如果在Eclipse的Eclemma插件中導(dǎo)入exec文件時(shí)彈窗椒惨,提示 “Error while loading coverage session (code 5001).”
    一般是因?yàn)閑clipse 中導(dǎo)入的項(xiàng)目編譯輸出文件夾目錄結(jié)構(gòu)不合法導(dǎo)致缤至,同時(shí) class 文件必須是從服務(wù)器中獲取的潮罪,不能使用 eclipse 自己的編譯器編譯的 class。由于 Eclipse 默認(rèn)會(huì)開啟自動(dòng)編譯领斥,所以哪怕你沒有手動(dòng)編譯嫉到,在你導(dǎo)入項(xiàng)目的時(shí)候 Eclipse 已經(jīng)幫你編譯了一次了。這里必須刪掉編譯后的 class 然后重新拷貝一份服務(wù)器上的 class 文件

導(dǎo)入失敗

4. 技術(shù)原理

運(yùn)行時(shí)分析 (Runtime Profilling) 技術(shù) 在 PureCoverage 中有使用月洛,他就是通過 JVMTI 來監(jiān)聽 JVM 的相關(guān)事件進(jìn)行覆蓋率數(shù)據(jù)收集何恶,而 Jacoco 則是使用字節(jié)碼注入(Byte Code Instrumentation)的方式,使用 ASM 庫在字節(jié)碼中插入 Probe 探針嚼黔,通過統(tǒng)計(jì)運(yùn)行時(shí)探針的覆蓋情況來統(tǒng)計(jì)覆蓋率信息细层。

技術(shù)原理

On-the-fly 模式:
JVM 中通過 javaagent 參數(shù)指定特定的 jar 文件啟動(dòng) Instrumentation 的代理程序惜辑,代理程序在通過 Class Loader 裝載一個(gè) class 前判斷是否轉(zhuǎn)換修改 class文件,將統(tǒng)計(jì)代碼插入 class疫赎,測(cè)試覆蓋率分析可以在 JVM 執(zhí)行測(cè)試代碼的過程中完成盛撑。

Offline 模式:
在測(cè)試前先對(duì)文件進(jìn)行插樁,然后生成插過樁的 class 或 jar 包捧搞,測(cè)試插過樁的 class 和 jar 包后抵卫,會(huì)生成動(dòng)態(tài)覆蓋信息到文件,最后統(tǒng)一對(duì)覆蓋信息進(jìn)行處理胎撇,并生成報(bào)告介粘。
存在如下情況不適合 on-the-fly,需要采用 offline 提前對(duì)字節(jié)碼插樁:

  1. 運(yùn)行環(huán)境不支持 java agent晚树。
  2. 部署環(huán)境不允許設(shè)置 JVM 參數(shù)姻采。
  3. 字節(jié)碼需要被轉(zhuǎn)換成其他的虛擬機(jī)如 Android Dalvik VM。
  4. 動(dòng)態(tài)修改字節(jié)碼過程中和其他 agent 沖突题涨。
  5. 無法自定義用戶加載類偎谁。

5. Ant 腳本

<?xml version="1.0" encoding="UTF-8" ?>
<project default="report" basedir="." xmlns:jacoco="antlib:org.jacoco.ant">

    <!-- 定義 Jacoco 相關(guān)變量和庫路徑 -->
    <property name="JacocoIP" value="192.168.22.33"/>
    <property name="JacocoPort" value="6300" />
    <property name="JacocoExec" value="./jacoco/merge-0608.exec" />
    <property name="JacocoReport" value="./jacoco/igaps-report.zip" />
    <property name="JacocoSrcPath" value="."/>
    <property name="JacocoClassPath" value="./igaps/apps"/>
    <property name="Encoding" value="UTF-8"/>
    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
        <classpath path="E:/jacoco/lib/jacocoant.jar"/>
    </taskdef>
    
   <!--  1 獲取覆蓋率exec文件 -->
   <target name="dump">
      <jacoco:dump address="${JacocoIP}" port="${JacocoPort}" reset="false" append="true" destfile="${JacocoExec}"  />
   </target>
   
   <!-- 2 合并exec文件 -->
   <!-- 獲取指定目錄下的所有 exec 文件并將數(shù)據(jù)合并為一個(gè)exec -->
   <target name="merge">
       <jacoco:merge destfile="./jacoco/merge.exec">
            <fileset dir="./jacoco/all" includes="*.exec" />
       </jacoco:merge>
   </target>

    <!-- 3 生成覆蓋率報(bào)告 -->
   <target name="report">
        <jacoco:report>
            
          <executiondata>
              <file file="${JacocoExec}" />
          </executiondata>
          
          <structure name="JaCoCo Report">          
              <group name="Core">
                  <classfiles>
                      <fileset dir="${JacocoClassPath}/lib/core" />
                  </classfiles>
                  <sourcefiles encoding="${Encoding}">
                        <fileset dir="${JacocoSrcPath}/src/monitor/timeout"/>
                        <fileset dir="${JacocoSrcPath}/src/tools/utils"/>
                        <fileset dir="${JacocoSrcPath}/src/redis/link"/>
                        <fileset dir="${JacocoSrcPath}/src/redis/util"/>
                        <fileset dir="${JacocoSrcPath}/src/server/init"/>
                        <fileset dir="${JacocoSrcPath}/src/grgbpm/core"/>
                        <fileset dir="${JacocoSrcPath}/src/grgbpm/handler"/>
                        <fileset dir="${JacocoSrcPath}/src/server/core"/>
                        <fileset dir="${JacocoSrcPath}/src/server/backend"/>
                        <fileset dir="${JacocoSrcPath}/src/server/exception"/>
                        <fileset dir="${JacocoSrcPath}/src/server/audit"/>
                        <fileset dir="${JacocoSrcPath}/src/server/dao"/>
                        <fileset dir="${JacocoSrcPath}/src/server/log"/>
                        <fileset dir="${JacocoSrcPath}/src/server/reload"/>
                        <fileset dir="${JacocoSrcPath}/src/server/business"/>                       
                        <fileset dir="${JacocoSrcPath}/src/component/service/http"/>
                        <fileset dir="${JacocoSrcPath}/src/component/service/https"/>
                        <fileset dir="${JacocoSrcPath}/src/component/service/webservice"/>
                        <fileset dir="${JacocoSrcPath}/src/component/unpack/separativesign"/>
                        <fileset dir="${JacocoSrcPath}/src/component/pack/separativesign"/>
                        <fileset dir="${JacocoSrcPath}/src/component/unpack/struct"/>
                        <fileset dir="${JacocoSrcPath}/src/component/pack/iso8583"/>
                        <fileset dir="${JacocoSrcPath}/src/component/pack/struct"/>
                        <fileset dir="${JacocoSrcPath}/src/component/unpack/xml"/>
                        <fileset dir="${JacocoSrcPath}/src/component/pack/xml"/>
                        <fileset dir="${JacocoSrcPath}/src/component/unpack/iso8583"/>
                        <fileset dir="${JacocoSrcPath}/src/component/service/tcp"/>
                        <fileset dir="${JacocoSrcPath}/src/component/communicate/ftp"/>
                        <fileset dir="${JacocoSrcPath}/src/component/communicate/http"/>
                        <fileset dir="${JacocoSrcPath}/src/component/communicate/https"/>
                        <fileset dir="${JacocoSrcPath}/src/component/communicate/webservice"/>
                        <fileset dir="${JacocoSrcPath}/src/component/communicate/tcp"/>
                        <fileset dir="${JacocoSrcPath}/src/component/timeout"/>
                        <fileset dir="${JacocoSrcPath}/src/component/endflow"/>
                        <fileset dir="${JacocoSrcPath}/src/component/logic"/>
                        <fileset dir="${JacocoSrcPath}/src/component/encryptor"/>
                        <fileset dir="${JacocoSrcPath}/src/component/judge"/>
                        <fileset dir="${JacocoSrcPath}/src/component/option"/>
                        <fileset dir="${JacocoSrcPath}/src/component/startflow"/>
                        <fileset dir="${JacocoSrcPath}/src/component/format"/>
                  </sourcefiles>
              </group>
              
              <group name="Project">           
                  <classfiles>
                      <fileset dir="${JacocoClassPath}/project"/>
                  </classfiles>
                  <sourcefiles encoding="${Encoding}">
                      <fileset dir="${JacocoSrcPath}/src/project">
                            <exclude name="config/**" />
                      </fileset>
                  </sourcefiles>
              </group>
          </structure>
          
          <html destfile="${JacocoReport}" encoding="${Encoding}" footer="${ReportFooter}"/>
          
      </jacoco:report>
   </target>   
  
</project>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纲堵,隨后出現(xiàn)的幾起案子巡雨,更是在濱河造成了極大的恐慌,老刑警劉巖席函,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铐望,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡茂附,警方通過查閱死者的電腦和手機(jī)正蛙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來营曼,“玉大人乒验,你說我怎么就攤上這事〉仝澹” “怎么了锻全?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)录煤。 經(jīng)常有香客問我鳄厌,道長(zhǎng),這世上最難降的妖魔是什么妈踊? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任了嚎,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘歪泳。我一直安慰自己萝勤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布呐伞。 她就那樣靜靜地躺著纵刘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荸哟。 梳的紋絲不亂的頭發(fā)上假哎,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音鞍历,去河邊找鬼舵抹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛劣砍,可吹牛的內(nèi)容都是我干的钟哥。 我是一名探鬼主播缰犁,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼给涕,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼垛叨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起装畅,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤靠娱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后掠兄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體像云,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年蚂夕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了迅诬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡婿牍,死狀恐怖侈贷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情等脂,我是刑警寧澤俏蛮,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站慎菲,受9級(jí)特大地震影響嫁蛇,放射性物質(zhì)發(fā)生泄漏锨并。R本人自食惡果不足惜露该,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望第煮。 院中可真熱鬧解幼,春花似錦抑党、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至特铝,卻和暖如春暑中,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鲫剿。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工鳄逾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灵莲。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓雕凹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親政冻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枚抵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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

  • ANT build.xml文件詳解(一) Ant的概念 可能有些讀者并不連接什么是Ant以及入可使用它,但只要使用...
    SkTj閱讀 3,975評(píng)論 0 2
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理明场,服務(wù)發(fā)現(xiàn)汽摹,斷路器,智...
    卡卡羅2017閱讀 134,637評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,778評(píng)論 6 342
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,694評(píng)論 0 3
  • “兩姓聯(lián)姻苦锨,一堂締約竖慧,良緣永結(jié),匹配同稱逆屡』迹看此日桃花灼灼,宜室宜家魏蔗,卜他年瓜瓞綿綿砍的,爾昌爾熾。謹(jǐn)以白頭之約莺治,書向鴻...
    夕噗閱讀 361評(píng)論 0 0