詳解Java類加載機制

一:ClassLoader

從JVM結(jié)構(gòu)圖中可以看到豪筝,類加載器的作用是將Java類文件加載到Java虛擬機腋颠。

HotSpot JVM結(jié)構(gòu)竖哩,圖片來自Java Garbage Collection Basics

只有當(dāng)類被加載進虛擬機內(nèi)存硅则,才能使用對應(yīng)的類厚者。

在Java中,類加載過程大概分為以下幾步:

  1. 通過全限類名獲取類文件字節(jié)數(shù)組。可來自本地文件膀篮、jar包、網(wǎng)絡(luò)等岂膳。
  2. 在方法區(qū)/元空間保存類的描述信息誓竿、靜態(tài)屬性。
  3. 在JVM堆中生成一個對應(yīng)的java.lang.Class對象谈截。

理解Java的類加載機制筷屡,對理解JVM有很大幫助。

二:Java默認(rèn)的類加載器

Java默認(rèn)提供三個類加載器簸喂,分別為:

  • Bootstrap ClassLoader
  • Extension ClassLoader
  • App ClassLoader

Bootstrap ClassLoader 負(fù)責(zé)加載Java基礎(chǔ)類速蕊,主要是 %JRE_HOME%/lib/ 目錄下的rt.jar、resources.jar娘赴、charsets.jar等。

Extension ClassLoader 負(fù)責(zé)加載Java擴展類跟啤,主要是 %JRE_HOME%/lib/ext 目錄下的jar诽表。

App ClassLoader 負(fù)責(zé)加載當(dāng)前應(yīng)用的ClassPath中的所有類。

三個ClassLoader所負(fù)責(zé)加載的類隅肥,可以通過以下方式進行查看竿奏。

public class ClassPath {
    public static void main(String[] args) {
        System.out.println("Bootstrap ClassLoader path: ");
        System.out.println(System.getProperty("sun.boot.class.path"));
        System.out.println("----------------------------");

        System.out.println("Extension ClassLoader path: ");
        System.out.println(System.getProperty("java.ext.dirs"));
        System.out.println("----------------------------");

        System.out.println("App ClassLoader path: ");
        System.out.println(System.getProperty("java.class.path"));
        System.out.println("----------------------------");
    }
}

具體原因,在源碼分析章節(jié)說明腥放。

其中Bootstrap ClassLoader是JVM級別的泛啸,由C++撰寫。

Extension ClassLoader和App ClassLoader都是Java類秃症。

JVM啟動Bootstrap ClassLoader候址,然后初始化sun.misc.Launcher。

接著种柑,Launcher初始化Extension ClassLoader和App ClassLoader岗仑。

三:源碼分析

sun.misc.Launcher類是Java程序的入口。

其構(gòu)造器如下:

public Launcher() {
    Launcher.ExtClassLoader var1;
    try {
        var1 = Launcher.ExtClassLoader.getExtClassLoader();
    } catch (IOException var10) {
        throw new InternalError("Could not create extension class loader", var10);
    }

    try {
        this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
    } catch (IOException var9) {
        throw new InternalError("Could not create application class loader", var9);
    }

    Thread.currentThread().setContextClassLoader(this.loader);
    ……
}

其中有兩行比較重要的代碼:

Launcher.ExtClassLoader.getExtClassLoader();

this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);

第一行初始化了ExtClassLoader聚请,但沒有指定其parent荠雕。

一些文章表示ExtClassLoader的父加載器是Bootstrap ClassLoader,這個說法其實并不完全準(zhǔn)確。

第二行初始化了AppClassLoader炸卑,指定ExtClassLoader作為其父加載器既鞠。并將AppClassLoader作為系統(tǒng)類加載器。

AppClassLoader將會成為自定義ClassLoader的默認(rèn)父加載器盖文。

具體邏輯可按照以下順序查看源代碼:

  1. Launcher類的getClassLoader()方法嘱蛋。
  2. ClassLoader類的initSystemClassLoader()方法。
  3. ClassLoader類的getSystemClassLoader()方法椅寺。
  4. ClassLoader類的ClassLoader()方法浑槽。

其中g(shù)etSystemClassLoader()方法的注釋為:

/**
* Returns the system class loader for delegation. This is the default
* delegation parent for new <tt>ClassLoader</tt> instances, and is
* typically the class loader used to start the application.
**/


ExtClassLoader和AppClassLoader都繼承了URLClassLoader類。

URLClassLoader支持從文件目錄和jar包加載class返帕。

ExtClassLoader和AppClassLoader都調(diào)用了父類的構(gòu)造函數(shù)桐玻。

public URLClassLoader(URL[] urls, ClassLoader parent,
                          URLStreamHandlerFactory factory)

URLClassLoader類中有個屬性為ucp,表示該ClassLoader負(fù)責(zé)搜索的路徑荆萤。

ExtClassLoader和AppClassLoader最大的不同镊靴,即它們負(fù)責(zé)的路徑不同。

/* The search path for classes and resources */
private final URLClassPath ucp;

查看源碼可得:

ExtClassLoader負(fù)責(zé)搜索的路徑為:

String var0 = System.getProperty("java.ext.dirs");

AppClassLoader負(fù)責(zé)搜索的路徑為:

String var1 = System.getProperty("java.class.path");

所以链韭,上一節(jié)可以通過這兩個方法獲取不同ClassLoader所負(fù)責(zé)加載的目錄偏竟。

此外,Bootstrap ClassLoader負(fù)責(zé)搜索的路徑為:

String bootClassPath = System.getProperty("sun.boot.class.path");

ClassLoader源碼

ClassLoader是一個抽象類敞峭,幾個主要的方法如下:

  • defineClass(String name, byte[] b, int off, int len)把字節(jié)數(shù)組b中的內(nèi)容轉(zhuǎn)換成Java類踊谋,返回的結(jié)果是java.lang.Class類的實例。

  • findClass(String name)查找名稱為name的類旋讹,返回的結(jié)果是java.lang.Class類的實例殖蚕。

  • loadClass(String name)加載名稱為name的類,返回的結(jié)果是java.lang.Class類的實例沉迹。

  • resolveClass(Class<?> c)鏈接指定的Java 類睦疫。

其中,loadClass方法是最常涉及的一個鞭呕。

其代碼如下:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

該方法主要的步驟如下:

  1. 指定全限類名進行加載蛤育,首先調(diào)用findLoadedClass(name)判斷當(dāng)前類加載器是否已經(jīng)加載該類。
  2. 如果沒有被加載葫松。則判斷當(dāng)前ClassLoader的父加載器是否為null瓦糕。如果不為null,則委托其父加載器進行加載进宝。如果為null刻坊,則使用Bootstrap ClassLoader進行加載。
  3. 如果父加載器或Bootstrap ClassLoader都無法加載党晋,則調(diào)用findClass(name)方法尋找需要加載的類谭胚。

此外徐块,loadClass方法還涉及加鎖的過程,使用ConcurrentHashMap對不同的全限類名進行加鎖灾而。

具體可查看getClassLoadingLock方法胡控。

四:雙親委托模式

Java類加載機制使用雙親委托模式。

一個ClassLoader加載一個類時旁趟,首先需要將任務(wù)委托給其父加載器昼激,直到Bootstrap ClassLoader。

如果父加載器未加載該類锡搜,則逐層返回給委托發(fā)起者即當(dāng)前ClassLoader進行加載橙困。

在正常應(yīng)用中,用戶不自定義類加載器耕餐。

類加載工作首先由App ClassLoader發(fā)起凡傅,然后委托給Extension ClassLoader,最后委托給Bootstrap ClassLoader肠缔。


首先夏跷,通過一個例子了解三個ClassLoader所負(fù)責(zé)加載的類和雙親委托模式。

新建一個jar包明未,名為acai-cl.jar槽华,包中有個簡單的Person類。

寫一個簡單的程序輸出person對象所對應(yīng)的ClassLoader趟妥。

import com.acai.Person;

public class TestClassLoader {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.getClass().getClassLoader());
    }
}

測試一:將jar包引入項目

jar包引入項目

對應(yīng)輸出:

sun.misc.Launcher$AppClassLoader@18b4aac2

可以看到猫态,位于ClassPath的類,是由App ClassLoader負(fù)責(zé)加載披摄。

測試二:將jar包復(fù)制到%JRE_HOME%/lib/ext目錄

復(fù)制到%JRE_HOME%/lib/ext

對應(yīng)輸出:

sun.misc.Launcher$ExtClassLoader@4cc77c2e

可以得出懂鸵,Extension ClassLoader負(fù)責(zé)加載%JRE_HOME%/lib/ext目錄下的類。

加載Person類時行疏,會首先嘗試使用App ClassLoader進行加載。

由于雙親委托模式套像,最終委托到Extension ClassLoader贞让,而其負(fù)責(zé)的目錄%JRE_HOME%/lib/ext下存在Person類销部,則進行了類加載操作。

測試三:將jar包追加到Bootstrap ClassLoader加載路徑上

追加到Bootstrap ClassLoader加載路徑

使用參數(shù):-Xbootclasspath/a:d:\acai-cl.jar撒妈,將jar包追加到Bootstrap ClassLoader加載路徑挟阻。

對應(yīng)輸出:

null

可以看出坷备,Person類的加載工作竟秫,最終被委托到了Bootstrap ClassLoader。

注:Bootstrap ClassLoader由C++撰寫纽谒。由Bootstrap ClassLoader負(fù)責(zé)加載的類,其getClassLoader()方法輸出為null。

可以嘗試輸出String類的類加載器眼虱。

System.out.println(String.class.getClassLoader());

接下來甥厦,再通過debug來驗證雙親委托模式。

還是原來那個簡單的demo疚鲤。

import com.acai.Person;

public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.getClass().getClassLoader());
    }
}

在ClassLoader類的loadClass方法上打斷點。

App ClassLoader嘗試加載
Extension ClassLoader嘗試加載
Bootstrap ClassLoader嘗試加載

可以看出缘挑,類的加載過程符合從下到上委托集歇,最終會被委托到Bootstrap ClassLoader。

同時符合從上到下加載语淘,每一層ClassLoader都會嘗試進行加載鬼悠。最終由App ClassLoader加載了Person類。

接著亏娜,嘗試加載一個特殊的類:Splash.class。

Splash類位于jfxrt.jar蹬挺,這個jar包在%JRE_HOME%/lib/ext目錄下维贺。

import com.sun.javafx.applet.Splash;

public class ExtTest {
    public static void main(String[] args) {
        Splash splash = new Splash(null);
        System.out.println(splash.getClass().getClassLoader());
    }
}

對應(yīng)輸出:

sun.misc.Launcher$ExtClassLoader@330bedb4

毫無疑問,Splash類應(yīng)該由Extension ClassLoader進行加載巴帮。

但其加載過程溯泣,仍然會從默認(rèn)的系統(tǒng)類加載器App ClassLoader開始虐秋。

可以通過debug進行查看。

App ClassLoader嘗試加載

Splash類加載的過程會被委托到Bootstrap ClassLoader垃沦,但Bootstrap ClassLoader并不負(fù)責(zé)加載%JRE_HOME%/lib/ext目錄下的類客给。最終由Extension ClassLoader進行加載。

Bootstrap ClassLoader嘗試加載未成功
最終由Extension ClassLoader加載

很多文章在闡述三個ClassLoader之間的關(guān)系時候肢簿,會給出一個getParent操作的demo靶剑。

并且認(rèn)為Bootstrap ClassLoader是Extension ClassLoader的父加載器。

Extension ClassLoader是App ClassLoader的父加載器池充。

App ClassLoader是自定義類加載器的父加載器桩引。

這樣的解釋基本正確,但Bootstrap ClassLoader和Extension ClassLoader之間的關(guān)系需要額外解釋收夸。

雙親委托機制坑匠,圖片來自參考7

由于Bootstrap ClassLoader并不是使用Java編寫,故無法指定Extension ClassLoader的parent為Bootstrap ClassLoader卧惜。

這一層關(guān)系在ClassLoader的loadClass方法中做了彌補厘灼。

在加載類時,會判斷當(dāng)前ClassLoader的父加載器是否為null咽瓷,為null則使用Bootstrap ClassLoader進行加載设凹。

在Java提供的三個默認(rèn)類加載器中,父加載器為null的只有Extension ClassLoader忱详。

該過程可參考ClassLoader的loadClass方法围来。


為什么使用雙親委托模式?

網(wǎng)上很多例子是關(guān)于String類匈睁。假設(shè)自己寫一個java.lang.String類监透,使用雙親委托模式可以防止這個問題。

但其實雙親委托模式可以被打破航唆,而真正阻止自定義java.lang.String的是“安全機制”胀蛮。

這里嘗試自定義java.lang.String類,并使用自定義ClassLoader進行加載糯钙。

package java.lang;

public class String {
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class StringClassLoader extends ClassLoader {
    @Override
    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        if ("java.lang.String".equals(name)) {
            return findClass(name);
        } else {
            return super.loadClass(name);
        }
    }

    @Override
    public Class<?> findClass(String s) throws ClassNotFoundException {
        try {
            byte[] classBytes = Files.readAllBytes(Paths.get("d:/String.class"));
            return defineClass(s, classBytes, 0, classBytes.length);
        } catch (IOException e) {
            throw new ClassNotFoundException(s);
        }
    }

    public static void main(String[] args) throws ClassNotFoundException {
        StringClassLoader stringClassLoader = new StringClassLoader();
        Class clazz = stringClassLoader.loadClass("java.lang.String", false);
        System.out.println(clazz.getClassLoader());
    }
}

該自定義類加載器破壞了雙親委托機制粪狼,具體方式將在下個章節(jié)說明。

輸出結(jié)果為:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang

可以看到任岸,在被findClass方法調(diào)用的defineClass中有這么一段:

if ((name != null) && name.startsWith("java.")) {
            throw new SecurityException
                ("Prohibited package name: " +
                 name.substring(0, name.lastIndexOf('.')));
        }

它會檢查當(dāng)前加載類的全限類名是否以java.開頭再榄,這也是一種安全機制。

如果按照網(wǎng)上的說法享潜,java.lang.String被Bootstrap ClassLoader加載困鸥,demo中自定義的類加載器會被略過,不會輸出異常剑按。

所以說疾就,雙親委托模式的作用只是防止類重復(fù)加載澜术。

五:自定義ClassLoader

多數(shù)情況下,Java默認(rèn)的三個類加載器已經(jīng)可以滿足需求猬腰。

自定義類加載器則可以實現(xiàn)額外的需求鸟废,例如:

  1. 從網(wǎng)絡(luò)文件加載類。
  2. 從任意目錄加載類姑荷。
  3. 對字節(jié)碼文件做加密處理盒延,由自定義類加載器做解密。

實現(xiàn)自定義類加載器的主要步驟為:

  1. 繼承ClassLoader類厢拭。如果只是從目錄或者jar包加載類兰英,也可以選擇繼承URLClassLoader類。
  2. 重寫findClass方法供鸠。
  3. 在重寫的findClass方法中畦贸,無論用何種方法,獲取類文件對應(yīng)的字節(jié)數(shù)組楞捂,然后調(diào)用defineClass方法轉(zhuǎn)換成類實例薄坏。

自定義類加載器真正好玩的是打破雙親委托機制,也是很多面試官會問到的問題寨闹。

上文提到類加載雙親委托模式實現(xiàn)位于ClassLoader的loadClass方法胶坠,想要破壞這個機制,則需要重寫該方法繁堡。

打破雙親委托模式的確有一定的實用價值沈善。

比如有兩個class文件,或者兩個jar包椭蹄。

其中兩個類的全限類名都一樣闻牡,如果需要同時使用這兩個類,則需要打破雙親委托模式绳矩。

有兩個Person類罩润,它們的全限類名均為com.acai.Person,唯一的區(qū)別是sayHello()方法輸出的內(nèi)容略有不同翼馆。

package com.acai;

import lombok.Data;

@Data
public class Person {

    private String name;

    private Integer age;

    public void sayHello() {
        System.out.println("Hello, this is Person in acai-cl");
    }
}
package com.acai;

import lombok.Data;

@Data
public class Person {

    private String name;

    private Integer age;

    public void sayHello() {
        System.out.println("Hello, this is Person in acai-cl2");
    }
}

將兩個Person所在的項目打成jar包割以。

兩個jar包

常規(guī)操作是,把兩個jar包都引進項目应媚。

寫一個小小的demo严沥。

import com.acai.Person;

public class Main {

    public static void main(String[] args) throws Exception {
        Person person = new Person();
        System.out.println(person.getClass().getClassLoader());
        person.sayHello();
    }
}

對應(yīng)輸出為:

sun.misc.Launcher$AppClassLoader@18b4aac2
Hello, this is Person in acai-cl

可以看到,demo中默認(rèn)使用了acai-cl.jar中的Person類中姜。

如果想要使用acai-cl2.jar中的Person類消玄,則想到新建一個ClassLoader。

需要從jar包加載類,則優(yōu)先想到URLClassLoader莱找。

import com.acai.Person;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class Main {

    public static void main(String[] args) throws Exception {
        Person person = new Person();
        System.out.println(person.getClass().getClassLoader());
        person.sayHello();

        URL url = new File("d:/acai-cl2.jar").toURI().toURL();
        URLClassLoader loader = new URLClassLoader(new URL[]{url});
        Thread.currentThread().setContextClassLoader(loader);
        Class<?> clazz = loader.loadClass("com.acai.Person");
        System.out.println(clazz.getClassLoader());
        Method method = clazz.getDeclaredMethod("sayHello");
        method.invoke(clazz.newInstance());
    }
}

對應(yīng)輸出:

sun.misc.Launcher$AppClassLoader@18b4aac2
Hello, this is Person in acai-cl

sun.misc.Launcher$AppClassLoader@18b4aac2
Hello, this is Person in acai-cl

可以看出,即使是指定了使用acai-cl2.jar嗜桌,輸出的仍然是acai-cl.jar中Person的sayHello奥溺。

原因是由于兩個Person類擁有一樣的全限類名。

加載第二個Person的時候骨宠,發(fā)現(xiàn)自定義類加載器的父類加載器App ClassLoader已經(jīng)加載了com.acai.Person浮定。

所以直接返回該類,即為acai-cl.jar中的Person類层亿。

于是想到桦卒,新建ClassLoader,并且破壞雙親委托機制匿又,重新loadClass方法方灾。

import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;

public class MyClassLoader extends URLClassLoader {


    public MyClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public MyClassLoader(URL[] urls) {
        super(urls);
    }

    public MyClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(urls, parent, factory);
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name.equals("com.acai.Person")) {
            return super.findClass(name);
        } else {
            return super.loadClass(name);
        }
    }
}

在MyClassLoader中重寫了loadClass方法,當(dāng)加載的類名等于com.acai.Person時碌更,直接調(diào)用findClass方法裕偿,繞過雙親委托機制。

這里需要一個if判斷痛单,表示只有在加載com.acai.Person時才破壞雙親委托嘿棘。

因為在加載一個類時,會同時加載它的父類旭绒。

Person的父類為java.lang.Object鸟妙。

直接用自定義類加載器加載Object類,會拋出SecurityException異常挥吵。

于是重父,寫一個demo。

import com.acai.Person;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class Main {

    public static void main(String[] args) throws Exception {
        Person person = new Person();
        System.out.println(person.getClass().getClassLoader());
        person.sayHello();

        URL url = new File("d:/acai-cl2.jar").toURI().toURL();
        URLClassLoader loader = new URLClassLoader(new URL[]{url});
        Thread.currentThread().setContextClassLoader(loader);
        Class<?> clazz = loader.loadClass("com.acai.Person");
        System.out.println(clazz.getClassLoader());
        Method method = clazz.getDeclaredMethod("sayHello");
        method.invoke(clazz.newInstance());

        URL url2 = new File("d:/acai-cl2.jar").toURI().toURL();
        MyClassLoader myClassLoader = new MyClassLoader(new URL[]{url2});
        Class<?> clazz2 = myClassLoader.loadClass("com.acai.Person");
        System.out.println(clazz2.getClassLoader());
        Method method2 = clazz2.getDeclaredMethod("sayHello");
        method2.invoke(clazz2.newInstance());
    }
}

sun.misc.Launcher$AppClassLoader@18b4aac2
Hello, this is Person in acai-cl

sun.misc.Launcher$AppClassLoader@18b4aac2
Hello, this is Person in acai-cl

MyClassLoader@5e2de80c
Hello, this is Person in acai-cl2

可以看到蔫劣,acai-cl2.jar中的Person類被正確加載坪郭。

得出,可以通過自定義ClassLoader脉幢,重寫loadClass歪沃,破壞雙親委托機制。

六:參考資料

[1] Java Garbage Collection Basics
[2] java classloader是怎么加載自身到內(nèi)存里面執(zhí)行的嫌松?
[3] 詳細(xì)深入分析 Java ClassLoader 工作機制
[4] 深入分析Java ClassLoader原理
[5] 深入探討 Java 類加載器
[6] 深度分析Java的ClassLoader機制(源碼級別)
[7] Java類加載原理與ClassLoader使用總結(jié)
[8] 實現(xiàn)java classloader 動態(tài)加載jar包
[9] ClassLoader的基礎(chǔ)詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沪曙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子萎羔,更是在濱河造成了極大的恐慌液走,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缘眶,居然都是意外死亡嘱根,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門巷懈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來该抒,“玉大人,你說我怎么就攤上這事顶燕〈毡#” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵涌攻,是天一觀的道長欧引。 經(jīng)常有香客問我,道長恳谎,這世上最難降的妖魔是什么芝此? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮惠爽,結(jié)果婚禮上癌蓖,老公的妹妹穿的比我還像新娘。我一直安慰自己婚肆,他們只是感情好租副,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著较性,像睡著了一般用僧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赞咙,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天责循,我揣著相機與錄音,去河邊找鬼攀操。 笑死院仿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的速和。 我是一名探鬼主播歹垫,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颠放!你這毒婦竟也來了排惨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤碰凶,失蹤者是張志新(化名)和其女友劉穎暮芭,沒想到半個月后鹿驼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡辕宏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年畜晰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瑞筐。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡舷蟀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出面哼,到底是詐尸還是另有隱情,我是刑警寧澤扫步,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布魔策,位于F島的核電站,受9級特大地震影響河胎,放射性物質(zhì)發(fā)生泄漏闯袒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一游岳、第九天 我趴在偏房一處隱蔽的房頂上張望政敢。 院中可真熱鬧,春花似錦胚迫、人聲如沸喷户。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽褪尝。三九已至,卻和暖如春期犬,著一層夾襖步出監(jiān)牢的瞬間河哑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工龟虎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留璃谨,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓鲤妥,卻偏偏與公主長得像佳吞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子旭斥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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