Android源碼設(shè)計模式學習筆記-代理模式

代理模式也稱為委托模式陡鹃,其實代理在我們?nèi)粘I钪胁⒉簧僖姾嫫郑瑢τ诔绦騿T來說最常接觸的莫過于代理上網(wǎng)了,代理模式在開發(fā)過程使用非常普遍.


image.png

通用模式代碼:

public abstract class Subject {
    public abstract void visit();
}
public class RealSubject extends Subject {
    @Override
    public void visit() {
        System.out.println("Real subject!");
    }
}
public class ProxySubject extends Subject {
    private RealSubject mSubject;
    public ProxySubject(RealSubject subject){
        this.mSubject = subject;
    }
    @Override
    public void visit() {
    }
}
public class Client {
    public static void main(String[] args){
        //構(gòu)造一個真實主題對象
        RealSubject realSubject = new RealSubject();

        //通過真實主題對象構(gòu)造一個代理對象
        ProxySubject proxySubject = new ProxySubject(realSubject);

        //調(diào)用代理的相關(guān)方法
        proxySubject.visit();
    }
}

角色介紹:
Subject : 抽象主題類
該類的主要職責是聲明真實主題與代理的共同接口方法萍鲸,該類可以是一個抽象類也可以是一個接口
RealSubject : 真實主題類
該類也成為被委托類或被代理類闷叉,該類定義了代理所表示的真實對象,???執(zhí)行具體的業(yè)務(wù)邏輯方法脊阴,而客戶類通過代理類間接地調(diào)用真實主題類中定義的方法
ProxySubject :代理類
該類也稱為委托類或代理類握侧,該類持有一個對真實主題類的引用,在其所實現(xiàn)的接口方法中調(diào)用真實主題類中相應(yīng)的接口方法執(zhí)行蹬叭,以此起到代理的作用
Client : 客戶類 使用代理類的類

代理模式的簡單實現(xiàn)

小明被拖欠工資藕咏,想走法律程序状知,找律師去申述這一個過程秽五,使用代理模式律師就是代理者,小明就是被代理的者饥悴,下面看看這樣一個過程坦喘,代碼應(yīng)該怎樣去實現(xiàn).

public interface ILawsuit {
    //提交申請
    void submit();
    //進行舉證
    void burden();
    //開始維護
    void defend();
    //訴訟完成
    void finish();
}
public class XiaoMin implements ILawsuit{
    @Override
    public void submit() {
        //老板欠小民工資 小小民只好申請仲裁
        System.out.println("老板拖欠工資,特此申請仲裁");
    }

    @Override
    public void burden() {
        //小民證據(jù)充足西设,不怕告不贏
        System.out.println("這是合同書和過去一年的銀行工資流水");
    }

    @Override
    public void defend() {
        //鐵證如山瓣铣,辯護也沒什么好說的
        System.out.println("證據(jù)確鑿! 不需要再說什么了");
    }

    @Override
    public void finish() {
        //結(jié)果也是肯定的,必贏
        System.out.println("訴訟成功! 判決老板即日起七天內(nèi)結(jié)算工資");
    }
}
public class Lawyer implements ILawsuit{

    private ILawsuit mILawsuit;

    public Lawyer(ILawsuit mILawsuit) {
        this.mILawsuit = mILawsuit;
    }

    @Override
    public void submit() {
    }

    @Override
    public void burden() {
    }

    @Override
    public void defend() {
    }

    @Override
    public void finish() {
    }
}
public class Client {
    public static void main(String[] args){
        ILawsuit xiaomin = new XiaoMin();
        //構(gòu)造代理律師
        ILawsuit lawsuit = new Lawyer(xiaomin);
        //律師提交訴訟申請
        lawsuit.submit();
        //律師進行舉證
        lawsuit.burden();
        //律師代替小民進行辯護
        lawsuit.defend();
        //完成訴訟
        lawsuit.finish();
    }
}

代理模式是一個非常重要的模式,它可以分為靜態(tài)代理和動態(tài)代理贷揽,靜態(tài)代理如上面所訴棠笑,代理類的代碼由開發(fā)者自己編寫;動態(tài)代理則與靜態(tài)代理相反禽绪,通過反射機制動態(tài)地生成代理者的對象蓖救,也就是我們code階段壓根就不需要知道代理誰,代理誰我們將會執(zhí)行階段決定.
下面繼續(xù)看


image.png

我們使用動態(tài)代理印屁,首先要定義一個InvocationHandler的子類循捺,我們命名為DynamicProxy

public class DynamicProxy implements InvocationHandler{

    private Object obj;    //被代理的類引用

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //調(diào)用被代理類對象的方法
        Object result = method.invoke(obj,args);
        return result;
    }
}

下面看下如何使用這個動態(tài)代理

public class Client {
    public static void main(String[] args){
        //構(gòu)造一個小民
        ILawsuit xiaomin = new XiaoMin();
        //構(gòu)造一個動態(tài)代理
        DynamicProxy proxy = new DynamicProxy(xiaomin);
        //獲取被代理類小民的ClassLoader
        ClassLoader loader = xiaomin.getClass().getClassLoader();
        //動態(tài)構(gòu)造一個代理者律師
        ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader,new Class[]{ILawsuit.class},proxy);
        //律師提交訴訟申請
        lawyer.submit();
        //律師進行舉證
        lawyer.burden();
        //律師代替小民進行辯護
        lawyer.defend();
        //完成訴訟
        lawyer.finish();
    }
}

輸出和前面靜態(tài)代理是一樣的,不過上面代碼可能還是有點疑惑雄人,我們一一解答下下面幾個問題

問題一:InvocationHandler在這個動態(tài)代理里面起到什么作用从橘?為什么通過Proxy.newProxyInstance可以生成一個動態(tài)代理對象?

解釋這一點,我們就需要去看看源代碼了,先看看InvocationHandler

public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

InvocationHandler就是一個接口恰力,里面有一個接口方法invoke叉谜,并傳入三個參數(shù)Object proxy, Method method, Object[] args。Object這種參數(shù)就不用說了踩萎,下面來看看Method到底是什么正罢,根據(jù)Method上面的注釋

/**
 * A {@code Method} provides information about, and access to, a single method
 * on a class or interface.  The reflected method may be a class method
 * or an instance method (including an abstract method).
 */
public final class Method extends Executable  {
}

它主要是獲取一個方法相關(guān)的信息,比如說getName()獲取方法名,getReturnType()獲取方法返回類型這些. 單單一個InvocationHandler其實也看不出來它的工作原理驻民,下面我們來看看newProxyInstance的源碼

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
    //1如果InvocationHandler為null就直接拋異常
        Objects.requireNonNull(h);
        final Class<?>[] intfs = interfaces.clone();
        //2獲取代理類
        Class<?> cl = getProxyClass0(loader, intfs);

        try {
        //3獲得構(gòu)造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                // Android-changed: Removed AccessController.doPrivileged
                cons.setAccessible(true);
            }
        //4實例話代理類翻具,注意這里傳入了InvocationHandler
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
        //代碼省略
        }
}

上面的代碼我們重點需要關(guān)注以下注釋2和注釋4,先來看看注釋2回还,如何獲取代理類裆泳,我們點擊去看

private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
        return proxyClassCache.get(loader, interfaces);
    }

通過proxyClassCache.get返回,proxyClassCache是什么柠硕?

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

再來看看get怎么實現(xiàn)的

//這里key class loader parameter是interface
public V get(K key, P parameter) {
    //1如果傳入interface參數(shù)為null就直接返回
    Objects.requireNonNull(parameter);
    expungeStaleEntries();
    Object cacheKey = CacheKey.valueOf(key, refQueue);
    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}

上面代碼我們其實就是一個沒有cache的時候put進去工禾,然后get, 有cache的時候就直接get這樣一個過程,我們重點看看它put和get什么就清楚最終它返回的是一個什么樣的代理類.
put(來自于上面源碼)

if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            }

get(來自于上面源碼)

if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }

其實put是存入Factory蝗柔,get呢是調(diào)用Factory的.get(Factory是Supplier的子類), 那么實際返回的代理類就是來自于Factory的get咯.

public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            if (supplier != this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            V value = null;
            try {
            //******************關(guān)注這里*******************
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // the only path to reach here is with non-null value
            assert value != null;

            // wrap value with CacheValue (WeakReference)
            CacheValue<V> cacheValue = new CacheValue<>(value);

            // try replacing us with CacheValue (this should always succeed)
            if (valuesMap.replace(subKey, this, cacheValue)) {
                // put also in reverseMap
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }

上面的valueFactory是ProxyClassFactory闻葵,ProxyClassFactory調(diào)用apply源碼如下

@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    //代碼省略
        return generateProxy(proxyName, interfaces, loader, methodsArray,
                             exceptionsArray);
    }
}
@FastNative
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
                                                 ClassLoader loader, Method[] methods,
                                                 Class<?>[][] exceptions);

generateProxy是native方法


image.png

我還不會跟進到native層,所以也不能繼續(xù)分析了. 不過總而言之getProxyClass0通過native層返回了一個代理類癣丧,注意這是個新類槽畔,里面有傳入的ClassLoader和interfaces作為成員變量,下面再來看看注釋4實例話代理類

cons.newInstance(new Object[]{h});

這里我們獲取到代理類后胁编,直接傳入?yún)?shù)h(InvocationHandler), 返回代理對象了.
最后結(jié)論是:native實現(xiàn)機制我暫時還不太清楚厢钧,不過大概來說native返回的代理對象會對被代理對象和InvocationHandler做一個關(guān)聯(lián),使得被代理對象沒調(diào)用一個函數(shù)都會回調(diào)到InvocationHandler的invoke方法中嬉橙,從而進行一個動態(tài)代理操作.

問題二早直,動態(tài)代理比靜態(tài)代理優(yōu)越在哪,什么時候使用動態(tài)代理市框?

通過實現(xiàn)和調(diào)用方式來看霞扬,使用動態(tài)代理就不需要再去定義靜態(tài)代理類了,代理過程是一個動態(tài)的適配枫振,在InvocationHandler的invoke去決定如何做這個代理過程. 什么時候用動態(tài)代理我覺得如果你的代理類存在很多喻圃,不方便用靜態(tài)實現(xiàn),就可以使用動態(tài)代理, 在Android中Retrofit框架就使用了動態(tài)代理技術(shù)蒋得,通常我們這樣創(chuàng)建Interface對象

PostRequest_Interface request = retrofit.create(PostRequest_Interface.class);

進入create源碼

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

它的所有動態(tài)代理邏輯都集中在

serviceMethod.callAdapter.adapt(okHttpCall)

詳情在這里也不多說了级及,大概就是這樣.

Android中的代理模式實現(xiàn)

我們來看看ActivityManagerProxy這個類,其具體代理的是ActivityManagerNative的子類ActivityManagerService.
ActivityManagerProxy實現(xiàn)了IActivityManager接口额衙,該接口定義了一些Activity相關(guān)的接口方法饮焦,其中有一些我們在應(yīng)用開發(fā)中也時常接觸到.
IActivityManager這個接口相當于代理模式中的抽象主題怕吴,那么真正的實現(xiàn)主題是ActivityManagerNative的ActivityManagerService類,這幾個類大致的關(guān)系:


image.png

ActivityManagerProxy實際上代理的是ActivityManagerService县踢,但是ActivityManagerProxy和ActivityManagerService是分別運行在不同的進程里(ActivityManagerProxy是運行在應(yīng)用的進程转绷,而ActivityManagerService是運行在系統(tǒng)進程),所以它們之間的這個代理過程是跨進程的硼啤,這里跨進程是用到Android的Binder集中完成. 不過ActivityManagerProxy在實際邏輯處理中并未過多地被外部類使用议经,因為在Android中管理與維護Activity相關(guān)信息的類是另外一個叫做ActivityManager的類,ActivityManager雖然說管理著Activity信息谴返,但是實質(zhì)上大多數(shù)邏輯由ActivityManagerProxy承擔煞肾,這里以其中的getAppTasks方法為例,在ActivityManager中g(shù)etAppTasks方法邏輯如下.

    public List<ActivityManager.AppTask> getAppTasks() {
        ArrayList<AppTask> tasks = new ArrayList<AppTask>();
        List<IBinder> appTasks;
        try {
            appTasks = getService().getAppTasks(mContext.getPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        int numAppTasks = appTasks.size();
        for (int i = 0; i < numAppTasks; i++) {
            tasks.add(new AppTask(IAppTask.Stub.asInterface(appTasks.get(i))));
        }
        return tasks;
    }

getService()其實返回的是一個IActivityManager嗓袱,那這個IActivityManager的實體類是什么呢籍救?

public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

ServiceManager.getService()返回的是一個系統(tǒng)級的Service, 這個Service實際上是ActivityManagerService,這里也完成創(chuàng)建一個對ActivityManagerService的Client代理對象ActivityManagerProxy實例.ActivityManagerProxy中的getAppTasks方法邏輯就很明確,將數(shù)據(jù)打包跨進程傳遞給Server端ActivityManagerService處理并返回結(jié)果.

public List<IAppTask> getAppTasks(String callingPackage) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeString(callingPackage);
        mRemote.transact(GET_APP_TASKS_TRANSACTION, data, reply, 0);
        reply.readException();
        ArrayList<IAppTask> list = null;
        int N = reply.readInt();
        if (N >= 0) {
            list = new ArrayList<>();
            while (N > 0) {
                IAppTask task = IAppTask.Stub.asInterface(reply.readStrongBinder());
                list.add(task);
                N--;
            }
        }
        data.recycle();
        reply.recycle();
        return list;
    }

再來看看ActivityManagerService中的getAppTasks

@Override
    public List<IAppTask> getAppTasks(String callingPackage) {
        int callingUid = Binder.getCallingUid();
        long ident = Binder.clearCallingIdentity();

        synchronized(this) {
            ArrayList<IAppTask> list = new ArrayList<IAppTask>();
            try {
                if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");

                final int N = mRecentTasks.size();
                for (int i = 0; i < N; i++) {
                    TaskRecord tr = mRecentTasks.get(i);
                    // Skip tasks that do not match the caller.  We don't need to verify
                    // callingPackage, because we are also limiting to callingUid and know
                    // that will limit to the correct security sandbox.
                    if (tr.effectiveUid != callingUid) {
                        continue;
                    }
                    Intent intent = tr.getBaseIntent();
                    if (intent == null ||
                            !callingPackage.equals(intent.getComponent().getPackageName())) {
                        continue;
                    }
                    ActivityManager.RecentTaskInfo taskInfo =
                            createRecentTaskInfoFromTaskRecord(tr);
                    AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
                    list.add(taskImpl);
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
            return list;
        }
    }

Android中的Binder跨進程通信機制

在Android中進程間通信我們通常使用到的是binder機制渠抹,binder機制所使用到的四個基本模塊是Binder Client, Binder Server, ServerManager和Binder Driver,這四者之間的關(guān)系類似與網(wǎng)絡(luò)訪問蝙昙,Binder Client相當于我們的客戶端pc , Binder Server相當于服務(wù)器,ServerManager相當于DNS服務(wù)器梧却,而Binder Driver則相當于一個路由器奇颠。其中Binder Driver實現(xiàn)在內(nèi)核空間中,而其余3者Binder Client, Binder Server, ServerManager實現(xiàn)在用戶空間中.

image.png

Binder Client與Binder Server之間的跨進程通信統(tǒng)一通過Binder Driver處理轉(zhuǎn)發(fā)放航,對于Binder Client來說烈拒,其只需要知道自己要使用的Binder的名字以及該Binder實體在ServerManager中的0號引用即可,訪問原理也比較簡單三椿,Binder Client先是通過0號引用去訪問ServerManager獲取Binder的引用缺菌,得到引用后就可以像普通方法那樣調(diào)用Binder實體方法。最后我們的ServerManager則用來管理Binder Server, Binder Client可以通過它來查詢Binder Server接口搜锰,剛才提到過Binder Client可以通過ServerManager來獲取Binder的引用,這個Binder引用就是由ServerManager來轉(zhuǎn)換的耿战。
image.png

如果再繼續(xù)說下去就有點蒙圈了. 還是按照簡單易懂的說法吧:
看這里蛋叼,你可以想象成Binder Driver就是一個管道,ServerManager是一個注冊表剂陡,所有的Binder Client和Binder Server都要在它那里注冊狈涮,Binder Client也通過ServerManager去查找對應(yīng)的Binder Server
最后,Binder Client和Binder Server其實實現(xiàn)的接口是一樣的鸭栖,所以大家可以聯(lián)想到Binder機制其實也是一種代理模式.

總結(jié)

代理模式是一種使用比較多的一種結(jié)構(gòu)性設(shè)計模式歌馍,這節(jié)通過一個通用模式代碼講解了代理模式的基本實現(xiàn)方案,然后又引入了一個小民打官司的栗子晕鹊,講解了如何去實現(xiàn)靜態(tài)代理和動態(tài)代理松却,然后深入了解了動態(tài)代理的實現(xiàn)原理和用處暴浦,最后講解了Android中有哪些地方用到了代理模式實現(xiàn).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市晓锻,隨后出現(xiàn)的幾起案子歌焦,更是在濱河造成了極大的恐慌,老刑警劉巖砚哆,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件独撇,死亡現(xiàn)場離奇詭異,居然都是意外死亡躁锁,警方通過查閱死者的電腦和手機纷铣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來战转,“玉大人关炼,你說我怎么就攤上這事∠坏酰” “怎么了儒拂?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長色鸳。 經(jīng)常有香客問我社痛,道長,這世上最難降的妖魔是什么命雀? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任蒜哀,我火速辦了婚禮,結(jié)果婚禮上吏砂,老公的妹妹穿的比我還像新娘撵儿。我一直安慰自己,他們只是感情好狐血,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布淀歇。 她就那樣靜靜地躺著,像睡著了一般匈织。 火紅的嫁衣襯著肌膚如雪浪默。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天缀匕,我揣著相機與錄音纳决,去河邊找鬼。 笑死乡小,一個胖子當著我的面吹牛阔加,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播满钟,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼胜榔,長吁一口氣:“原來是場噩夢啊……” “哼胳喷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起苗分,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤厌蔽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摔癣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奴饮,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年择浊,在試婚紗的時候發(fā)現(xiàn)自己被綠了戴卜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仔粥,到底是詐尸還是另有隱情辽旋,我是刑警寧澤眶蕉,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏啄育。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一拌消、第九天 我趴在偏房一處隱蔽的房頂上張望挑豌。 院中可真熱鬧,春花似錦墩崩、人聲如沸氓英。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铝阐。三九已至,卻和暖如春盛龄,著一層夾襖步出監(jiān)牢的瞬間饰迹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工余舶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锹淌。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓匿值,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赂摆。 傳聞我的和親對象是個殘疾皇子挟憔,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

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