面試必考之類的加載器

類加載器簡介

類加載器負(fù)責(zé)在運行時將Java class動態(tài)加載到JVM(Java虛擬機(jī))屈溉。而且垒手,它們是JRE(Java運行時環(huán)境)的一部分。 因此,由于類加載器的緣故马昨,JVM無需了解底層文件或文件系統(tǒng)即可運行Java程序匹舞。

而且稍坯,這些Java class不會一次全部加載到內(nèi)存中俊鱼,而是在應(yīng)用程序需要時加載。 這是類加載器發(fā)揮作用的時候锹安, 他們負(fù)責(zé)將類加載到內(nèi)存中短荐。

在本篇內(nèi)容中,我們將討論不同類型的內(nèi)置類加載器叹哭,它們?nèi)绾喂ぷ饕约白远x實現(xiàn)的介紹忍宋。

內(nèi)置的類加載器類型

讓我們從一個簡單的示例開始學(xué)習(xí)如何使用各種類加載器加載不同的類:

public class ClassLoaderTest {
    @Test
    public void printClassLoaders() throws ClassNotFoundException {
        System.out.println("Classloader of this class:" + ClassLoaderTest.class.getClassLoader());

        System.out.println("Classloader of Logging:" + Logging.class.getClassLoader());

        System.out.println("Classloader of ArrayList:" + ArrayList.class.getClassLoader());
    }
}

// console output
Classloader of this class:sun.misc.Launcher$AppClassLoader@18b4aac2
Classloader of Logging:sun.misc.Launcher$ExtClassLoader@65b54208
Classloader of ArrayList:null

如我們所見,這里有三種不同的類加載器: AppClassLoader风罩,ExtClassLoader和BootstrapClassLoader (顯示為null)糠排。

AppClassLoader 加載示例方法的類. 應(yīng)用或系統(tǒng)類加載器加載classpath下的類文件.

接下來, ExtClassLoader加載 Logging class. ExtensionClassLoaders 加載作為標(biāo)準(zhǔn)核心Java類的擴(kuò)展的類.

但是, 我們看到最后一個的輸出, 對于ArrayList,輸出顯示為 null . 這是因為BootstrapClassLoader 是用native code編寫的, 而非Java – 因此它不會顯示為Java class. 由于這個原因超升,引導(dǎo)類加載器的行為在不同JVM之間會有所不同入宦。

總體而言,下圖顯示了不同類加載器之間的聯(lián)系和區(qū)別:


java class loader delegates.png

接下來我們詳細(xì)討論這些類加載器室琢。

Bootstrap Class Loader

Java classes 由 java.lang.ClassLoader的實例加載. 但是, ClassLoaders 它們本身也是類. 那么問題來了, 誰來加載 java.lang.ClassLoader 本身呢?

這正是圖中引導(dǎo)程序或原始類裝載器應(yīng)用的地方乾闰。

它主要負(fù)責(zé)加載JDK內(nèi)部類, 通常是 rt.jar$JAVA_HOME/jre/lib 目錄中的其他核心庫. 此外, Bootstrap 類加載器還充當(dāng)其他 ClassLoader instances的父類.

Bootstrap ClassLoader 是 JVM 核心的重要內(nèi)容部分,它是用Native Code編寫的 . 不同的平臺( HotSpot 盈滴、 JRockit 涯肩、 J9 )可能對它有不同的實現(xiàn)方式.

Extension Class Loader

Extension ClassLoader 是Bootstrap ClassLoader的子類,負(fù)責(zé)加載標(biāo)準(zhǔn)核心 Java 的拓展類, 以便在平臺上運行整個應(yīng)用程序.

Extension ClassLoader 從 JDK 拓展目錄, 通常是$JAVA_HOME/lib/ext 目錄或者 java.ext.dirs 系統(tǒng)屬性設(shè)置的目錄.

System Class Loader

另一方面,System ClassLoader(有的稱之為Application ClassLoader)負(fù)責(zé)加載應(yīng)用級別的classes 到 JVM 中. 它負(fù)責(zé)加載classpath 環(huán)境變量下的文件, -classpath-cp 命令行選項中的文件. 而且病苗,它是Extension ClassLoader的子類疗垛。

ClassLoader如何工作?

ClassLoaders 是 Java運行環(huán)境的一部分. JVM 請求一個類時, ClassLoader將使用完全限定名去定位該類铅乡,并加載到j(luò)vm運行時環(huán)境中.

java.lang.ClassLoader.loadClass() 方法負(fù)責(zé)將類定義加載到運行時. 它嘗試使用完全限定名去加載類.

如果該類尚未被加載, 它將委托父類加載器去加載. 這是一個遞歸過程.

最終, 如果父類加載器沒有找到該類, 則子類將調(diào)用 java.net.URLClassLoader.findClass() 方法在自己的文件系統(tǒng)中尋找該類.

如果最后一個子類也無法加載該類, 則會拋出java.lang.NoClassDefFoundErrorjava.lang.ClassNotFoundException.

讓我們看一個拋出ClassNotFoundException的輸出示例继谚。

Exception in thread "main" java.lang.ClassNotFoundException: com.bern.classloader.SampleClassLoader
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)

如果我們從調(diào)用java.lang.Class.forName()開始查看事件軸烈菌,我們發(fā)現(xiàn)阵幸,它首先艙室通過父類加載器加載該類,然后通過java.net.URLClassLoader.findClass() 查找類本身. 當(dāng)依舊無法找到該類芽世,它將拋出 ClassNotFoundException

類加載器有三個重要的特性挚赊。

委托模型

ClassLoaders 遵循委托模型,在該模型中,根據(jù)請求查找class 或者 resource, ClassLoader實例將會委托給父類加載器去尋找class或者resource.

假設(shè)我們需要將應(yīng)用程序類加載到JVM中的請求济瓢。 AppClassLoader首先將該類的加載委托給其父類Extension ClassLoader荠割,而Extension ClassLoader又將其委托給Bootstrap ClassLoader。

僅當(dāng)Bootstrap 和 Extension ClassLoader 未能成功加載該類時, Application ClassLoader才會艙室加載該類.

唯一性

作為委托模型的結(jié)果,很容易確保 唯一的類旺矾,因為我們總是嘗試向上委托. 如果父類加載器沒有找到該類, 則當(dāng)前的實例才會去嘗試尋找該類.

可見性

另外, 子ClassLoaders 對其父ClassLoaders加載的類可見.例如System ClassLoader加載的類對Extension ClassLoader和Bootstrap ClassLoader加載的類可見蔑鹦,反過來卻不可以。

為了說明這一點, 如果Class A 是由Application ClassLoader加載的箕宙, class B 是由Extensions ClassLoader加載的, 則就Application ClassLoader加載的其他類而言 嚎朽,A 和 B 都是可見的.

但是,就Extensions ClassLoader加載的其他類而言柬帕,類B是唯一可見的類哟忍。

Custom ClassLoader

在大多數(shù)情況下,內(nèi)置的類加載器就足夠了陷寝。 但是锅很,在需要從本地硬盤驅(qū)動器以外或網(wǎng)絡(luò)中加載類的情況下,我們可能需要使用自定義類加載器凤跑。接下來爆安,我們將介紹自定義類加載器的一些用例場景,并創(chuàng)建一個示例仔引。

Custom Class Loaders Use-Cases

自定義類加載器不僅在運行時加載類有用鹏控,還包括如下一些使用場景:

1、幫助修改現(xiàn)有的字節(jié)碼肤寝,例如 weaving agents 当辐。

2、動態(tài)創(chuàng)建適合用戶需求的類鲤看。 例如在JDBC中缘揪,通過動態(tài)類加載實現(xiàn)不同驅(qū)動程序之間的切換。

3、在具有相同名稱和包的類的情況下找筝,通過加載不同的字節(jié)碼實現(xiàn)版本控制機(jī)制蹈垢。這可以通過URL類加載器(通過URL加載jar)或自定義類加載器來完成。

在更具體的示例中袖裕,自定義類加載器可能會派上用場曹抬。 例如,瀏覽器使用自定義類加載器從網(wǎng)絡(luò)加載可執(zhí)行內(nèi)容. 瀏覽器可以使用單獨的類加載器從不同的網(wǎng)頁加載applet. 用于運行applets 的 applet viewer包含一個ClassLoader, 該ClassLoader可訪問遠(yuǎn)程服務(wù)器上的網(wǎng)站急鳄,而無需在本地文件系統(tǒng)查找內(nèi)容谤民。然后通過HTTP加載原始字節(jié)碼文件,并將其裝載到JVM中. 即使這些applets具有相同的名稱, 但如果由不同的類加載器加載,它們也被視為不同的組件. 現(xiàn)在疾宏,我們已經(jīng)對自定義ClassLoader的使用場景有了一些了解张足,接下來讓我們通過一個自定義 ClassLoader 深入的理解JVM如何加載classes.

Creating our Custom Class Loader

下面的示例創(chuàng)建一個自定義的ClassLoader ,并從文件中讀取class加載到JVM中坎藐, 我們需要繼承ClassLoader類并重寫 findClass()方法:

package com.bern.classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class CustomClassLoader extends ClassLoader {

    @Override
    public Class findClass(String name) throws ClassNotFoundException {
        byte[] b = loadClassFromFile(name);
        return defineClass(name, b, 0, b.length);
    }

    private byte[] loadClassFromFile(String fileName)  {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(
                fileName.replace('.', File.separatorChar) + ".class");
        byte[] buffer;
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        int nextValue = 0;
        try {
            while ( (nextValue = inputStream.read()) != -1 ) {
                byteStream.write(nextValue);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        buffer = byteStream.toByteArray();
        return buffer;
    }
}

深入理解java.lang.ClassLoader

我們接下來了解以下 java.lang.ClassLoader 類中的一些重要方法为牍,以便能夠更好的理解它的工作方式.

loadClass() 方法

public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {

此方法負(fù)責(zé)加載給定name參數(shù)的類. name 參數(shù)必須是類的完全限定名. 如果resolve 參數(shù)設(shè)置為true, 則Java虛擬機(jī)調(diào)用loadClass() 方法來解析class 引用. 但是, 并不一定非要解析一個類. 如果我們只想確定該類是否存在,而無需去解析, 只需要將參數(shù) resolve 設(shè)置為false即可.** 此方法是類加載器的入口點岩馍。 我們可以通過查看java.lang.ClassLoader 的源碼來了解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;
        }
    }

該方法的默認(rèn)實現(xiàn)按以下順序搜索類:

  1. 調(diào)用findLoadedClass(String) 方法查看該類是否已經(jīng)被加載.
  2. 調(diào)用父類加載器的 loadClass(String) 方法查找該類.
  3. 如果父類加載器沒有找到碉咆,則調(diào)用 findClass(String) 方法查找該類.

defineClass() 方法

protected final Class<?> defineClass(String name, byte[] b, int off, int len)    throws ClassFormatError

此方法負(fù)責(zé)將字節(jié)數(shù)組轉(zhuǎn)換為類的實例. 在使用該類之前, 我們需要先對它進(jìn)行解析. 如果類的格式不正確, 則會拋出一個ClassFormatError異常. 另外, 因為該方法時final類型,所以我們無法對它進(jìn)行重寫.

findClass() 方法

protected Class<?> findClass(String name) throws ClassNotFoundException {    throw new ClassNotFoundException(name);}

該方法使用完全限定名作為參數(shù)來查找class. 我們需要在自定義ClassLoader中重寫該方法. 如果父ClassLoader找不到請求的類蛀恩,則 loadClass() 會調(diào)用此方法疫铜。 如果所有的父ClassLoader沒有找到該類,則默認(rèn)實現(xiàn)將會拋出 ClassNotFoundException 異常.

getParent() 方法

public final ClassLoader getParent() 

此方法返回父類加載器進(jìn)行委派. 有些JVM實現(xiàn)(如第二部分)使用null表示Bootstrap ClassLoader.

getResource() 方法

public URL getResource(String name) {

此方法用來查找給定名稱的資源(資源的名稱是用 / 分隔的路徑名).

它首先委托父加載器查找資源. 如果 parent 返回null, 則搜索虛擬機(jī)內(nèi)置的類加載器的路徑. ** 如果都失敗了, 則該方法將調(diào)用 findResource(String) 來查找資源. 資源名稱相對于classpath來說可以是相對路徑赦肋,也可以是絕對路徑. 它通過讀取資源块攒,返回一個URL 對象, 如果沒有找到該資源,或者沒有權(quán)限讀取該資源佃乘,則返回null. 特別需要要注意的是囱井,Java是從 classpath 加載資源。 最后, Java中的資源加載被認(rèn)為是與位置無關(guān)的 因為只是根據(jù)設(shè)置的環(huán)境變量來查找資源趣避,代碼在何處運行都無關(guān)緊要.

Context Classloaders

通常, Context ClassLoaders 為 J2SE引入類加載委托方案提供了一種替代方法. 就像我們之前所學(xué)的, JVM中的類加載器遵循分層模型庞呕,因此除了Bootstrap ClassLoader,每個類加載器都有且僅有一個父級. 但是, 有時當(dāng)JVM核心類需要動態(tài)加載應(yīng)用程序級別的類或資源時, 我們可能會遇到一些問題. 例如, 在JNDI中程帕,核心功能由 rt.jar 中的Bootstrap Classes 實現(xiàn). 但是這些 JNDI classes 可能會加載由 JNDI 獨立供應(yīng)商提供的JNDI的實現(xiàn) (部署在應(yīng)用的 classpath). 這種情況要求Bootstrap ClassLoader (父類加載器) 加載的類對Application ClassLoader (子類加載器)可見. J2SE 委托模型不能解決這種問題住练,為了解決這個問題, 我們需要找到替代的類加載方式. 我們可以使用線程上下文加載器來應(yīng)對這種場景. java.lang.Thread 類有一個 getContextClassLoader()方法,該方法返回特定線程的ContextClassLoader . 當(dāng)加載類或資源時愁拭,線程的創(chuàng)建者提供ContextClassLoader . 如果沒有設(shè)置上下文加載器, 默認(rèn)是父線程的上下文加載器.

類加載器與 OSGi

OSGi?是 Java 上的動態(tài)模塊系統(tǒng)讲逛。它為開發(fā)人員提供了面向服務(wù)和基于組件的運行環(huán)境,并提供標(biāo)準(zhǔn)的方式用來管理軟件的生命周期岭埠。OSGi 已經(jīng)被實現(xiàn)和部署在很多產(chǎn)品上盏混,在開源社區(qū)也得到了廣泛的支持蔚鸥。Eclipse 就是基于 OSGi 技術(shù)來構(gòu)建的。

OSGi 中的每個模塊(bundle)都包含 Java 包和類许赃。模塊可以聲明它所依賴的需要導(dǎo)入(import)的其它模塊的 Java 包和類(通過 Import-Package)止喷,也可以聲明導(dǎo)出(export)自己的包和類,供其它模塊使用(通過 Export-Package)混聊。也就是說需要能夠隱藏和共享一個模塊中的某些 Java 包和類弹谁。這是通過 OSGi 特有的類加載器機(jī)制來實現(xiàn)的。OSGi 中的每個模塊都有對應(yīng)的一個類加載器句喜。它負(fù)責(zé)加載模塊自己包含的 Java 包和類预愤。當(dāng)它需要加載 Java 核心庫的類時(以 java開頭的包和類),它會代理給父類加載器(通常是啟動類加載器)來完成藤滥。當(dāng)它需要加載所導(dǎo)入的 Java 類時鳖粟,它會代理給導(dǎo)出此 Java 類的模塊來完成加載社裆。模塊也可以顯式的聲明某些 Java 包和類拙绊,必須由父類加載器來加載。只需要設(shè)置系統(tǒng)屬性org.osgi.framework.bootdelegation的值即可泳秀。

假設(shè)有兩個模塊 bundleA 和 bundleB标沪,它們都有自己對應(yīng)的類加載器 classLoaderA 和 classLoaderB。在 bundleA 中包含類com.bundleA.Sample嗜傅,并且該類被聲明為導(dǎo)出的金句,也就是說可以被其它模塊所使用的。bundleB 聲明了導(dǎo)入 bundleA 提供的類 com.bundleA.Sample吕嘀,并包含一個類 com.bundleB.NewSample繼承自 com.bundleA.Sample违寞。在 bundleB 啟動的時候,其類加載器 classLoaderB 需要加載類 com.bundleB.NewSample偶房,進(jìn)而需要加載類 com.bundleA.Sample趁曼。由于 bundleB 聲明了類 com.bundleA.Sample是導(dǎo)入的,classLoaderB 把加載類 com.bundleA.Sample的工作代理給導(dǎo)出該類的 bundleA 的類加載器 classLoaderA棕洋。classLoaderA 在其模塊內(nèi)部查找類 com.bundleA.Sample并定義它挡闰,所得到的類 com.bundleA.Sample實例就可以被所有聲明導(dǎo)入了此類的模塊使用。對于以 java開頭的類掰盘,都是由父類加載器來加載的摄悯。如果聲明了系統(tǒng)屬性org.osgi.framework.bootdelegation=com.example.core.*,那么對于包 com.example.core中的類愧捕,都是由父類加載器來完成的奢驯。

OSGi 模塊的這種類加載器結(jié)構(gòu),使得一個類的不同版本可以共存在 Java 虛擬機(jī)中次绘,帶來了很大的靈活性瘪阁。不過它的這種不同典蜕,也會給開發(fā)人員帶來一些麻煩,尤其當(dāng)模塊需要使用第三方提供的庫的時候罗洗。下面提供幾條比較好的建議:

  • 如果一個類庫只有一個模塊使用愉舔,把該類庫的 jar 包放在模塊中,在 Bundle-ClassPath中指明即可伙菜。

  • 如果一個類庫被多個模塊共用轩缤,可以為這個類庫單獨的創(chuàng)建一個模塊,把其它模塊需要用到的 Java 包聲明為導(dǎo)出的贩绕。其它模塊聲明導(dǎo)入這些類火的。

  • 如果類庫提供了 SPI 接口,并且利用線程上下文類加載器來加載 SPI 實現(xiàn)的 Java 類淑倾,有可能會找不到 Java 類馏鹤。如果出現(xiàn)了 NoClassDefFoundError異常,首先檢查當(dāng)前線程的上下文類加載器是否正確娇哆。通過Thread.currentThread().getContextClassLoader()就可以得到該類加載器湃累。該類加載器應(yīng)該是該模塊對應(yīng)的類加載器。如果不是的話碍讨,可以首先通過 class.getClassLoader()來得到模塊對應(yīng)的類加載器治力,再通過Thread.currentThread().setContextClassLoader()來設(shè)置當(dāng)前線程的上下文類加載器。

總結(jié)

ClassLoaders對于執(zhí)行Java程序至關(guān)重要. 本文詳細(xì)的講解了相關(guān)的知識. 我們具體的討論了不同類型的加載器 – Bootstrap, Extensions 和 System ClassLoaders. Bootstrap ClassLoader是所有ClassLoader的父級勃黍,并負(fù)責(zé)加載 JDK 內(nèi)部 classes. Extensions 和 system, 分別加載從 Java 拓展目錄和 classpath 加載類. 然后宵统,我們討論了類加載器的工作原理,并討論了一些它們的特性覆获,如委托模型马澈,可見性,唯一性. 然后講解了如何創(chuàng)建一個自定義的ClassLoader. 最后, we provided an introduction to Context class loaders. 然后弄息,我們討論了類加載器的工作方式痊班,并討論了一些功能,例如委托疑枯,可見性和唯一性辩块,然后簡要說明了如何創(chuàng)建自定義的。 然后荆永,我們介紹了上下文類加載器废亭。最后,我們介紹了osgi和類加載器的關(guān)系具钥。

所有代碼都已經(jīng)上傳至 GitHub.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豆村,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子骂删,更是在濱河造成了極大的恐慌掌动,老刑警劉巖四啰,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異粗恢,居然都是意外死亡柑晒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門眷射,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匙赞,“玉大人,你說我怎么就攤上這事妖碉∮客ィ” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵欧宜,是天一觀的道長坐榆。 經(jīng)常有香客問我,道長冗茸,這世上最難降的妖魔是什么席镀? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮蚀狰,結(jié)果婚禮上愉昆,老公的妹妹穿的比我還像新娘职员。我一直安慰自己麻蹋,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布焊切。 她就那樣靜靜地躺著扮授,像睡著了一般。 火紅的嫁衣襯著肌膚如雪专肪。 梳的紋絲不亂的頭發(fā)上刹勃,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天,我揣著相機(jī)與錄音嚎尤,去河邊找鬼荔仁。 笑死,一個胖子當(dāng)著我的面吹牛芽死,可吹牛的內(nèi)容都是我干的乏梁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼关贵,長吁一口氣:“原來是場噩夢啊……” “哼遇骑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起揖曾,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤落萎,失蹤者是張志新(化名)和其女友劉穎亥啦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體练链,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡翔脱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了媒鼓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碍侦。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖隶糕,靈堂內(nèi)的尸體忽然破棺而出瓷产,到底是詐尸還是另有隱情,我是刑警寧澤枚驻,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布濒旦,位于F島的核電站,受9級特大地震影響再登,放射性物質(zhì)發(fā)生泄漏尔邓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一锉矢、第九天 我趴在偏房一處隱蔽的房頂上張望梯嗽。 院中可真熱鬧,春花似錦沽损、人聲如沸灯节。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炎疆。三九已至,卻和暖如春国裳,著一層夾襖步出監(jiān)牢的瞬間形入,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工缝左, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留亿遂,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓渺杉,卻偏偏與公主長得像蛇数,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子少办,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354