Retrofit源碼分析二 代理模式

Retrofit源碼分析二 代理模式

上一節(jié)我們講了一些Retrofit的概覽面哼,這一節(jié)我們主要來(lái)說(shuō)一下代理模式橡疼。有同學(xué)可能要問(wèn)素邪,這不是Retrofit的源碼分析嗎,怎么都第二節(jié)了還不分析源碼呢卸伞?其實(shí)Retrofit這個(gè)框架中應(yīng)用了很多的設(shè)計(jì)模式抹镊,其中最重要的就是動(dòng)態(tài)代理模式。如果我們要理解并掌握Retrofit荤傲,那么就必須先掌握代理模式垮耳。代理模式主要分為兩種,靜態(tài)代理和動(dòng)態(tài)代理遂黍,下面我們來(lái)細(xì)細(xì)的說(shuō)明一下终佛。

靜態(tài)代理

靜態(tài)代理.jpg

從上面的類圖中我們可以了解到,RealClass和ProxyClass都繼承了AbstractClass雾家,都實(shí)現(xiàn)AbstractClass中的operation方法铃彰。其中ProxyClass包含了一個(gè)RealClass的引用,在調(diào)用ProxyClass中的operation方法時(shí)芯咧,調(diào)用了RealClass類型的引用對(duì)象的operation方法牙捉,這就是靜態(tài)代理。只是這么說(shuō)有些抽象敬飒,下面我們來(lái)看一個(gè)具體的代碼實(shí)現(xiàn)邪铲。

package com.blackflagbin.frameanalysis.staticproxy;

//抽象日志類
public abstract class AbstractLogger {
    abstract public void log();
}
package com.blackflagbin.frameanalysis.staticproxy;

//真實(shí)操作日志類,繼承AbstractLogger
public class RealLogger extends AbstractLogger {
    @Override
    public void log() {
        System.out.println("show some log");
    }
}
package com.blackflagbin.frameanalysis.staticproxy;

//代理日志類无拗,包含一個(gè)真實(shí)日志類的實(shí)例带到,在打印日志之前校驗(yàn)權(quán)限
public class ProxyLogger extends AbstractLogger {

    private AbstractLogger mLogger;

    public ProxyLogger(AbstractLogger logger) {
        mLogger = logger;
    }

    private boolean checkPermission() {
        return true;
    }

    @Override
    public void log() {
        if (checkPermission()) {
            mLogger.log();
        } else {
            System.out.println("you have no access");
        }
    }
}

上面三個(gè)類分別是抽象日志類、真實(shí)日志類英染、代理日志類揽惹。抽象日志類定義了一個(gè)打印日志的接口被饿,真實(shí)日志類繼承了抽象日志,并實(shí)現(xiàn)的這個(gè)打印日志的方法搪搏。這個(gè)時(shí)候狭握,我們想要在打印日志前加上權(quán)限校驗(yàn),又不想直接修改我們的真實(shí)日志類慕嚷,那么就需要使用的靜態(tài)代理模式哥牍。為了實(shí)現(xiàn)在打印日志前校驗(yàn)權(quán)限的功能,我們創(chuàng)建了一個(gè)新類喝检,代理日志類,這個(gè)類同樣繼承了抽象日志類撼泛,關(guān)鍵的是包含了一個(gè)真實(shí)日志類的引用對(duì)象挠说。在這個(gè)代理類中的log方法中,通過(guò)在調(diào)用真實(shí)日志引用對(duì)象的log方法之前加入權(quán)限校驗(yàn)愿题,從而實(shí)現(xiàn)了上述的功能损俭。

動(dòng)態(tài)代理

動(dòng)態(tài)代理與靜態(tài)代理最大的區(qū)別在于動(dòng)態(tài)。那么問(wèn)題來(lái)了潘酗,這個(gè)動(dòng)態(tài)體現(xiàn)在哪里杆兵,又該如何去理解?
這個(gè)動(dòng)態(tài)關(guān)鍵在于代理類的創(chuàng)建時(shí)機(jī)仔夺。靜態(tài)代理中的代理類在我們運(yùn)行程序之前是必須要存在的琐脏,而動(dòng)態(tài)代理中的代理類則是在程序運(yùn)行時(shí)創(chuàng)建的。前半句很好理解缸兔,代理類的代碼肯定是先存在日裙,然后才能運(yùn)行,這個(gè)邏輯很符合我們平常的開(kāi)發(fā)模式惰蜜。問(wèn)題就在于后半句昂拂,代理類在運(yùn)行時(shí)創(chuàng)建,運(yùn)行時(shí)如何創(chuàng)建代理類抛猖?這是不是很反邏輯格侯?代碼都沒(méi)有,怎么來(lái)根據(jù)我們的需求來(lái)代理真實(shí)的被代理的對(duì)象财著?諸位稍安勿躁联四,我們接下來(lái)會(huì)對(duì)動(dòng)態(tài)代理進(jìn)行詳細(xì)的解釋。
動(dòng)態(tài)代理有兩種實(shí)現(xiàn)方式:

  1. JDK動(dòng)態(tài)代理
  2. CGLIB
    我們?cè)谶@里主要講解JDK動(dòng)態(tài)代理瓢宦。JDK動(dòng)態(tài)代理底層是通過(guò)Java的反射實(shí)現(xiàn)的碎连,而且只能為接口創(chuàng)建動(dòng)態(tài)代理,而靜態(tài)代理則沒(méi)有這種限制(接口或者抽象類都可以)驮履。下面我們通過(guò)一些代碼來(lái)看一下動(dòng)態(tài)代理的實(shí)現(xiàn)方式鱼辙。同樣廉嚼,我們使用打印日志的這個(gè)例子,方便大家理解倒戏。
package com.blackflagbin.frameanalysis.dynamicproxy;

//日志接口(動(dòng)態(tài)代理不同于靜態(tài)代理怠噪,只能使用接口)
public interface ILogger {
    void log();
}
package com.blackflagbin.frameanalysis.dynamicproxy;

//真實(shí)日志類,實(shí)現(xiàn)日志接口
public class RealLogger implements ILogger {
    @Override
    public void log() {
        System.out.println("show some log");
    }
}
package com.blackflagbin.frameanalysis.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyHandler implements InvocationHandler {

    //被代理對(duì)象(即目標(biāo)對(duì)象)的實(shí)例杜跷,在打印日志這個(gè)例子中對(duì)應(yīng)RealLogger的實(shí)例
    private final Object mTarget;

    public ProxyHandler(Object target) {
        mTarget = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (checkPermission()) {
            System.out.println("you have access");
            //被代理對(duì)象(即目標(biāo)對(duì)象)方法的調(diào)用
            return method.invoke(mTarget, args);
        } else {
            System.out.println("you have no access");
            return null;
        }
    }

    //創(chuàng)建實(shí)際的代理對(duì)象
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(mTarget.getClass().getClassLoader(), mTarget.getClass().getInterfaces(), this);
    }

    private boolean checkPermission() {
        return true;
    }

}
package com.blackflagbin.frameanalysis.dynamicproxy;

//測(cè)試類
public class Test {
    public static void main(String[] args) {
        ProxyHandler proxyHandler = new ProxyHandler(new RealLogger());
        ILogger proxy = (ILogger) proxyHandler.getProxyInstance();
        proxy.log();
    }
}
/*
最終打印結(jié)果:
you have access
show some log
 */

日志接口和真實(shí)日志類沒(méi)什么可說(shuō)的傍念,跟靜態(tài)代理一樣,只不過(guò)因?yàn)閯?dòng)態(tài)代理必須要使用接口所以把抽象類換成了接口葛闷。
動(dòng)態(tài)代理實(shí)現(xiàn)打印日志這個(gè)例子的關(guān)鍵在于ProxyHandler這個(gè)類憋槐。我們知道,在靜態(tài)代理中淑趾,對(duì)原有功能進(jìn)行擴(kuò)展或修改的代碼實(shí)現(xiàn)是在靜態(tài)代理類中定義的阳仔。也就是在ProxyLogger中添加額外的權(quán)限校驗(yàn)方法,并修改打印日志的流程扣泊。那么問(wèn)題來(lái)了近范,在動(dòng)態(tài)代理中,動(dòng)態(tài)代理類是在程序運(yùn)行時(shí)生成的延蟹,我們并沒(méi)有事先聲明一個(gè)動(dòng)態(tài)代理類评矩,這個(gè)對(duì)原有功能進(jìn)行擴(kuò)展或修改的代碼實(shí)現(xiàn)究竟要放在哪里?
問(wèn)題的答案在這個(gè)打印日志的例子里已經(jīng)很明確了阱飘,對(duì)原有功能進(jìn)行擴(kuò)展或修改的代碼實(shí)現(xiàn)放在了一個(gè)類中斥杜,這個(gè)類實(shí)現(xiàn)了InvocationHandler這個(gè)接口。我們通過(guò)對(duì)invoke這個(gè)方法的修改來(lái)修改被代理對(duì)象的方法實(shí)現(xiàn)俯萌,通過(guò)在invoke方法中的method.invoke(mTarget, args)之前或之后插入我們想要的邏輯來(lái)增對(duì)原有功能進(jìn)行擴(kuò)展果录。
在這個(gè)ProxyHandler類中,我們還添加了一個(gè)getProxyInstance()方法來(lái)創(chuàng)建代理類對(duì)象咐熙。通過(guò)Proxy.newProxyInstance(mTarget.getClass().getClassLoader(), mTarget.getClass().getInterfaces(), this)來(lái)創(chuàng)建代理類的實(shí)例是固定的寫(xiě)法弱恒,newProxyInstance需要傳入三個(gè)參數(shù),分別是類加載器棋恼、接口數(shù)組和實(shí)現(xiàn)InvocationHandler的類的實(shí)例對(duì)象返弹。
我們?cè)賮?lái)總結(jié)一下。無(wú)論是靜態(tài)代理還是動(dòng)態(tài)代理爪飘,它們的本質(zhì)都是代理對(duì)象包含一個(gè)被代理對(duì)象的實(shí)例义起,從而對(duì)被代理對(duì)象的原有功能進(jìn)行擴(kuò)展或修改。最大的區(qū)別是代理類的創(chuàng)建時(shí)機(jī)不同师崎,靜態(tài)代理必須在程序運(yùn)行前寫(xiě)好代理類默终;而動(dòng)態(tài)代理的代理類則不需要我們手動(dòng)提前寫(xiě)好,它會(huì)在運(yùn)行時(shí)創(chuàng)建相應(yīng)的代理類。 值得再次強(qiáng)調(diào)的是齐蔽,雖然動(dòng)態(tài)代理不需要我們?cè)诖a中實(shí)現(xiàn)代理類两疚,但是對(duì)原有功能進(jìn)行擴(kuò)展或修改的代碼實(shí)現(xiàn)是必須提前寫(xiě)好的。這個(gè)很好理解含滴,如果開(kāi)發(fā)人員都不寫(xiě)清楚要如何對(duì)原有功能進(jìn)行擴(kuò)展或修改诱渤,計(jì)算機(jī)又怎么知道呢?所以對(duì)原有功能進(jìn)行擴(kuò)展或修改的代碼實(shí)現(xiàn)就必須提前寫(xiě)好谈况,問(wèn)題是這些代碼要放在那里勺美,為了解決這個(gè)問(wèn)題,Java提供了一個(gè)InvocationHandler的接口碑韵,我們只要把相應(yīng)的代碼放到這個(gè)接口的實(shí)現(xiàn)類中即可赡茸。生成的代理對(duì)象在調(diào)用相應(yīng)的方法時(shí),實(shí)際上調(diào)用的是invoke這個(gè)方法泼诱,從而實(shí)現(xiàn)了對(duì)被代理對(duì)象的原有功能進(jìn)行擴(kuò)展或修改坛掠。
最后,我再貼上一些代碼治筒。

package com.zhidian.cloudforpolice.common.http

import com.zhidian.cloudforpolice.BuildConfig
import com.zhidian.cloudforpolice.common.entity.http.*
import com.zhidian.cloudforpolice.common.entity.http.Unit
import io.reactivex.Observable
import retrofit2.http.*

/**
 * Created by blackflagbin on 2018/1/27.
 */
interface ApiService {

    //登錄
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}account/login.do")
    fun login(@Field("username") userName: String, @Field("password") pwd: String, @Field("clientType") clientType: Int): Observable<HttpResultEntity<UserEntity>>

    //登出
    @POST("${BuildConfig.EXTRA_URL}account/logout.do")
    fun logout(): Observable<HttpResultEntity<Any>>

    //獲取小區(qū)列表
    @GET("${BuildConfig.EXTRA_URL}community/name/list")
    fun getCommunityList(): Observable<HttpResultEntity<List<CommunityEntity>>>

    //獲取首頁(yè)信息
    @GET("${BuildConfig.EXTRA_URL}count/communityStatistic/{communityId}.do")
    fun getMainData(@Path("communityId") communityId: Int): Observable<HttpResultEntity<MainEntity>>

    //根據(jù)小區(qū)id獲取小區(qū)樓幢列表
    @GET("${BuildConfig.EXTRA_URL}community/block/name/list/{communityId}")
    fun getBuildingList(@Path("communityId") communityId: Int): Observable<HttpResultEntity<List<BuildingEntity>>>

    //根據(jù)樓幢id獲取樓棟下的房間列表
    @GET("${BuildConfig.EXTRA_URL}community/block/detail/{blockId}")
    fun getRoomList(@Path("blockId") blockId: Int): Observable<HttpResultEntity<BuildingInfoEntity>>

    //根據(jù)單元id獲取單元下樓層列表
    @GET("${BuildConfig.EXTRA_URL}community/unit/query/{unitId}")
    fun getFloorList(@Path("unitId") unitId: Int): Observable<HttpResultEntity<Unit>>

    //根據(jù)房間id獲取房間詳情
    @GET("${BuildConfig.EXTRA_URL}community/room/detail/{roomId}")
    fun getRoomInfo(@Path("roomId") roomId: Int): Observable<HttpResultEntity<RoomInfoEntity>>

    //根據(jù)條件查詢,獲取符合條件的居民列表
    @GET("${BuildConfig.EXTRA_URL}community/resident/list/{pageNo}/{limit}")
    fun getSearchedPersonList(
            @Path("pageNo") pageNo: Int, @Path(
                    "limit") limit: Int, @QueryMap map: Map<String, String>): Observable<HttpResultEntity<PersonEntity>>

    //根據(jù)用戶id獲取關(guān)聯(lián)房屋列表
    @GET("${BuildConfig.EXTRA_URL}community/resident/room/list/{userId}")
    fun getRelatedRoomList(@Path("userId") userId: Int): Observable<HttpResultEntity<List<RelatedRoomEntity>>>

    //獲取樓幢詳情
    @GET("${BuildConfig.EXTRA_URL}count/blockStatistic/{buildingId}.do")
    fun getBuildingDetail(@Path("buildingId") buildingId: Int): Observable<HttpResultEntity<BuildingDetailEntity>>

    //獲取一級(jí)標(biāo)簽
    @GET("${BuildConfig.EXTRA_URL}user/label/parent/list")
    fun getFirstLabel(): Observable<HttpResultEntity<List<LabelItemEntity>>>

    //獲取二級(jí)標(biāo)簽
    @GET("${BuildConfig.EXTRA_URL}user/label/child/list/{parentId}")
    fun getSecondLabel(@Path("parentId") parentId: Int): Observable<HttpResultEntity<List<LabelItemEntity>>>

    //修改密碼
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}account/password/update")
    fun changePwd(@Field("password") oldPwd: String, @Field("newPsw") newPwd: String): Observable<HttpResultEntity<Any>>


    //門禁在線
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}device/query")
    fun getDeviceList(@Field("communityId") communityId: Int, @Field("pageNo") pageNo: Int, @Field("limit") limit: Int): Observable<HttpResultEntity<DoorEntity>>


    //獲取門禁狀態(tài)
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}device/selectDeviceStatusCount")
    fun getDeviceStatusList(@Field("communityId") communityId: Int): Observable<HttpResultEntity<List<DeviceStatusItem>>>


    //根據(jù)條件查詢舷蒲,獲取警情處理規(guī)范列表
    @GET("${BuildConfig.EXTRA_URL}police/handle/norm/list/{pageNo}/{limit}")
    fun getPoliceHandleList(
            @Path("pageNo") pageNo: Int, @Path(
                    "limit") limit: Int, @QueryMap map: Map<String, String>): Observable<HttpResultEntity<PoliceHandleEntity>>

    //根據(jù)條件查詢耸袜,獲取重點(diǎn)人員預(yù)警列表
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}police/person/query")
    fun getPersonPreWarningList(
            @FieldMap map: Map<String, String>): Observable<HttpResultEntity<PersonPreWarningEntity>>


    //根據(jù)條件查詢,獲取觸警人員預(yù)警列表
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}police/person/queryContactPolice")
    fun getAttackPreWarningList(
            @FieldMap map: Map<String, String>): Observable<HttpResultEntity<PersonPreWarningEntity>>


    //根據(jù)條件查詢牲平,獲取重點(diǎn)房屋預(yù)警列表
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}police/room/query")
    fun getRoomPreWarningList(
            @FieldMap map: Map<String, String>): Observable<HttpResultEntity<RoomPreWarningEntity>>

    //獲取行為軌跡
    @GET("${BuildConfig.EXTRA_URL}user/info/live/history/{userId}")
    fun getMovePath(
            @Path("userId") userId: String): Observable<HttpResultEntity<List<MovePathItemEntity>>>

    //開(kāi)門
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}device/operate/1")
    fun openLock(
            @Field("devicdId") deviceId: String): Observable<HttpResultEntity<Any>>

    //更新人員預(yù)警狀態(tài)
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}police/person/updStatu")
    fun updatePersonPreWaning(
            @Field("id") id: String, @Field("statu") status: Int, @Field("processContent") processContent: String): Observable<HttpResultEntity<Any>>

    //更新房屋預(yù)警狀態(tài)
    @FormUrlEncoded
    @POST("${BuildConfig.EXTRA_URL}police/room/updStatu")
    fun updateRoomPreWaning(
            @Field("id") id: String, @Field("statu") status: Int, @Field("processContent") processContent: String): Observable<HttpResultEntity<Any>>


    //獲取二維碼返回結(jié)果
    @FormUrlEncoded
    @POST("api/qrcode/parsingcode")
    fun getQrCodeResult(
            @Field("code") qrcode: String): Observable<HttpResultEntity<String>>


}

這是個(gè)Kotlin寫(xiě)的接口類堤框,用過(guò)Retrofit的同學(xué)應(yīng)該很清楚,使用Retrofit進(jìn)行網(wǎng)絡(luò)請(qǐng)求纵柿,首先就是要?jiǎng)?chuàng)建一個(gè)網(wǎng)絡(luò)請(qǐng)求接口類蜈抓。

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://......../")
    .build();

ApiService service = retrofit.create(ApiService.class);

看到ApiService service = retrofit.create(ApiService.class)有沒(méi)有很熟悉的感覺(jué)?聰明的小伙伴看到這里應(yīng)該就會(huì)明白了昂儒,沒(méi)錯(cuò)沟使,這其實(shí)就是通過(guò)動(dòng)態(tài)代理創(chuàng)建了一個(gè)代理對(duì)象。我們只是寫(xiě)了一個(gè)網(wǎng)絡(luò)接口類渊跋,里面什么都沒(méi)實(shí)現(xiàn)腊嗡,為什么就可以正確的請(qǐng)求網(wǎng)絡(luò)并包裝返回的數(shù)據(jù)結(jié)果?如果你從上到下把這篇文章看完了拾酝,即使你現(xiàn)在還并不清楚里面具體的代碼細(xì)節(jié)燕少,但有一點(diǎn)你會(huì)非常明確:我們寫(xiě)的ApiService這個(gè)接口類并不具有訪問(wèn)網(wǎng)絡(luò)并包裝返回?cái)?shù)據(jù)結(jié)果的功能,是Retrofit通過(guò)動(dòng)態(tài)代理的方式為我們生成了一個(gè)代理對(duì)象蒿囤,為我們的接口方法擴(kuò)展了網(wǎng)絡(luò)訪問(wèn)的功能客们。理解這一點(diǎn),對(duì)我們后續(xù)的源碼分析非常重要。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末底挫,一起剝皮案震驚了整個(gè)濱河市恒傻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凄敢,老刑警劉巖碌冶,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涝缝,居然都是意外死亡扑庞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拒逮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)罐氨,“玉大人,你說(shuō)我怎么就攤上這事滩援≌ひ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵玩徊,是天一觀的道長(zhǎng)租悄。 經(jīng)常有香客問(wèn)我,道長(zhǎng)恩袱,這世上最難降的妖魔是什么泣棋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮畔塔,結(jié)果婚禮上潭辈,老公的妹妹穿的比我還像新娘。我一直安慰自己澈吨,他們只是感情好把敢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著谅辣,像睡著了一般修赞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屈藐,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天榔组,我揣著相機(jī)與錄音,去河邊找鬼联逻。 笑死搓扯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的包归。 我是一名探鬼主播锨推,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了换可?” 一聲冷哼從身側(cè)響起椎椰,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沾鳄,沒(méi)想到半個(gè)月后慨飘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡译荞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年瓤的,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吞歼。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡圈膏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出篙骡,到底是詐尸還是另有隱情稽坤,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布糯俗,位于F島的核電站尿褪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏得湘。R本人自食惡果不足惜茫多,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忽刽。 院中可真熱鬧,春花似錦夺欲、人聲如沸跪帝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)伞剑。三九已至,卻和暖如春市埋,著一層夾襖步出監(jiān)牢的瞬間黎泣,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工缤谎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抒倚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓坷澡,卻偏偏與公主長(zhǎng)得像托呕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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