Proxy代理者模式(一)

摘要

本篇筆記針對(duì)Java設(shè)計(jì)模式中最難理解的代理者模式進(jìn)行講解,從靜態(tài)代理彤灶、動(dòng)態(tài)代理旷太,及Java相關(guān)代理類的應(yīng)用等幾個(gè)方面講解展懈。

一、簡(jiǎn)介

主要內(nèi)容:
1供璧、由問(wèn)題引出設(shè)計(jì)模式
2存崖、靜態(tài)代理的產(chǎn)生與實(shí)現(xiàn)
3、繼承與聚合哪個(gè)好
4睡毒、動(dòng)態(tài)代理的產(chǎn)生與實(shí)現(xiàn)
5来惧、JDK proxy的實(shí)現(xiàn)及應(yīng)用
6、總結(jié)與補(bǔ)充

二演顾、問(wèn)題引出

在實(shí)際應(yīng)用中供搀,我們經(jīng)常要對(duì)一些類的的功能進(jìn)行一些日志啊隅居,權(quán)限驗(yàn)證等操作,事務(wù)控制等處理葛虐,而這些類很多都是打成jar包的胎源,本就看不到源碼、別說(shuō)修改了屿脐。那我們?cè)趺崔k涕蚤?問(wèn)題就來(lái)了:如何在不修改一個(gè)類的代碼的情況下去實(shí)現(xiàn)我們想要的上述的功能?比如性能測(cè)試中我們想知道某個(gè)方法的執(zhí)行時(shí)間是多少摄悯?

三赞季、靜態(tài)代理

1愧捕、簡(jiǎn)單靜態(tài)代理

為了解決以上問(wèn)題奢驯,我們首先想到的就是
1、自己寫一個(gè)類繼承其它被代理類次绘。
2瘪阁、在main方法中調(diào)用父類的被測(cè)試方法之前記錄當(dāng)前系統(tǒng)時(shí)間作為起始時(shí)間。
3邮偎、調(diào)用被測(cè)試方法管跺、調(diào)用完之后記錄結(jié)束時(shí)間、并輸出時(shí)間差禾进、這就是要測(cè)試的方法的執(zhí)行時(shí)間豁跑。下面Java模仿實(shí)現(xiàn)代碼
a)假設(shè)Car使我們看不到的源碼類、它有一個(gè)run方法泻云,我們想測(cè)試其運(yùn)行時(shí)間

package com.mmb.proxy;
import java.util.Random;
public class Car {
public void running()
{
    System.out.println("Car is runing");
    try
    {
        Thread.sleep(new Random().nextInt(1000));
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}
}

b) 我們自己定義個(gè)CarTimeProxy類艇拍、繼承Car類、那么我們自己定義的類就擁有了使用Car類的running方法宠纯、那就可以實(shí)現(xiàn)測(cè)試執(zhí)行時(shí)間卸夕。CarTimeProxy——代碼:

package com.mmb.proxy;
public class CarTimeProxy extends Car {
@Override
public void running() {
    long startTime = System.currentTimeMillis();
    System.out.println("start time is " + startTime);
    super.running();
    long endTime = System.currentTimeMillis();
    System.out.println("end time is " + endTime);
    System.out.println("it takes " + (endTime-startTime) + " ms");
}
}

4、Client代碼:package com.mmb.proxy;

public class Client {
public static void main(String[] args) {
    CarTimeProxy carTimeProxy = new CarTimeProxy();
    carTimeProxy.running();
}
}

5婆瓜、測(cè)試結(jié)果

start time is 1433255852213
Car is runing
end time is 1433255853199
it takes 986 ms

2快集、靜態(tài)代理的進(jìn)一步實(shí)現(xiàn)

上面完美的解決了對(duì)一個(gè)類的一個(gè)方法的一種處理方式、看起來(lái)我們的RunTimeProxy是不是有點(diǎn)代理的樣子了廉白?但是明顯上面有很大的局限性个初、甚至可以說(shuō)是缺陷!那就是沒有用到我們常常掛在嘴邊的抽象猴蹂、多態(tài)院溺。當(dāng)然這么講可能覺得不理解、沒有直觀的印象晕讲。問(wèn)題:當(dāng)我想換一個(gè)會(huì)跑的對(duì)象(比如狗覆获,馬)來(lái)測(cè)試一下他跑的方法的執(zhí)行時(shí)間的時(shí)候怎么辦马澈?是不是只能重新寫一個(gè)我們自己的類來(lái)繼承動(dòng)物類、然后重復(fù)上邊的步驟弄息?很顯然痊班、這樣的做法沒有任何我們覺得可取的優(yōu)點(diǎn)。只會(huì)將時(shí)間浪費(fèi)在重復(fù)的coding代碼中摹量。
對(duì)與會(huì)飛的東西涤伐、我們第一想法應(yīng)該是可以抽象出他們共同的特性——會(huì)跑、那么我們可不可以定義一個(gè)runAble接口缨称、提供一個(gè)running方法呢凝果、這樣想具有跑的功能就實(shí)現(xiàn)這個(gè)接口就ok了。
到了上面一步睦尽、距離我們想要的結(jié)構(gòu)就更近一步了器净、那就是使用聚合的形式將被代理類與代理類相結(jié)合!這樣我們?cè)谝粋€(gè)代理類中就可以對(duì)任意實(shí)現(xiàn)了我們規(guī)定的接口的實(shí)現(xiàn)類進(jìn)行我們想要的處理当凡、可能這樣講有點(diǎn)迷惑山害、直接通過(guò)代碼來(lái)、在上面的代碼基礎(chǔ)上修改即可:

1沿量、添加一個(gè)RunAble接口浪慌、里面就一個(gè)running方法——RunAble代碼:

 package com.mmb.proxy;
 public interface RunAble {
 public void running();
   }

2、讓想要具有跑的功能的類都實(shí)現(xiàn)個(gè)這個(gè)接口朴则。Dog代碼:Horse代碼:

package com.mmb.proxy;

import java.util.Random;
public class Horse extends RunAble {
@Override
public void running() {
    System.out.println("Horse is runing");
    try
    {
        Thread.sleep(new Random().nextInt(1000));
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}
}

package com.mmb.proxy;

import java.util.Random;
public class Dog implements RunAble {
@Override
public void running() {
    System.out.println("Dog is running");
    try
    {
        Thread.sleep(new Random().nextInt(1000));
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}
}

3权纤、此時(shí)的代理類——RunAbleTimeProxy(此時(shí)再叫RunTimeProxy就不合適了、因?yàn)樗F(xiàn)在是所有能飛的東西的時(shí)間代理類)代碼:

package com.mmb.proxy;
public class RunAbleTimeProxy implements RunAble{
private RunAble runAbleObject;

public RunAbleTimeProxy(RunAble runAbleObject)
{
    super();
    this.runAbleObject = runAbleObject;
}

@Override
public void running() {
    long startTime = System.currentTimeMillis();
    System.out.println("start time is " + startTime);
    runAbleObject.running();
    long endTime = System.currentTimeMillis();
    System.out.println("end time is " + endTime);
    System.out.println("it takes " + (endTime-startTime) + " ms");
}
}

4乌妒、為了正規(guī)點(diǎn)我們另起一個(gè)Client測(cè)試代理類:

 package com.mmb.proxy;
 public class RunAbleClient {
public static void main(String[] args) {
    RunAbleTimeProxy runAbleTimeProxy = new RunAbleTimeProxy(new Dog());
    runAbleTimeProxy.running();
}
}

5汹想、測(cè)試結(jié)果:

start time is 1433256898668
Dog is running
end time is 1433256899343
it takes 675 ms

3、靜態(tài)代理的更進(jìn)一步實(shí)現(xiàn)

上面的代碼就顯得有點(diǎn)能看了芥被、最起碼我們?cè)诶锩婺苷业蕉鄳B(tài)欧宜、接口這些東西的使用、同時(shí)也解決了一個(gè)代理可以代理具有同一特性的類(這里就是多態(tài)的強(qiáng)大與靈活)拴魄、但是設(shè)計(jì)是無(wú)止境的冗茸!一個(gè)問(wèn)題的解決往往伴隨這新的問(wèn)題的出現(xiàn):如果我想要對(duì)fly方法進(jìn)行日志記錄、怎么辦匹中?你腦海中的第一反應(yīng)可能會(huì)是再寫一個(gè)類RunAbleLogProxy夏漱、沒錯(cuò)!這本身就是一種解決辦法顶捷、更好的解決方法下面會(huì)有挂绰、這里不是重點(diǎn)、重點(diǎn)是——我既想記錄時(shí)間服赎、又想記錄日志葵蒂、怎么辦交播?寫第三個(gè)代理類:RunAbleLogAndTimeProxy。好吧践付、繼續(xù)來(lái)問(wèn)題:我想先記錄時(shí)間秦士、在記錄日志?之后又想先記錄日志再記錄時(shí)間永高?之后我覺得還應(yīng)該添加一個(gè)事務(wù)控制隧土、然后他們?nèi)齻€(gè)的順序我還想換換?然后我覺得還應(yīng)該加個(gè)權(quán)限控制命爬。曹傀。。饲宛。皆愉。。不要覺得我犯賤落萎、想這想那亥啦。炭剪。练链。問(wèn)題真的來(lái)臨的時(shí)候你怎么解決?難道每出現(xiàn)一個(gè)新的變動(dòng)就要寫一個(gè)新的代理類奴拦?那要寫多少媒鼓?什么時(shí)候是個(gè)頭?想解決問(wèn)題错妖、還是得找Java的多態(tài)绿鸣、抽象。四個(gè)字說(shuō)起來(lái)簡(jiǎn)單暂氯、真真正正的用的時(shí)候你才會(huì)體會(huì)到他的博大精深潮模!解決方法:
我們有沒有想過(guò)代理類也是類?也可以被其他的代理類所代理痴施?條件無(wú)非就是和原始的被代理類實(shí)現(xiàn)同一個(gè)接口擎厢!然后可以根據(jù)不同的需求順序來(lái)調(diào)整他們的代理順序?比如我先使用記錄時(shí)間的類來(lái)代理被代理類辣吃、然后使用記錄日志的代理類來(lái)代理記錄時(shí)間的代理類动遭?這樣是不是實(shí)現(xiàn)了先記錄時(shí)間后記錄日志的代理?如果有多個(gè)神得、我們完全可以按照這種方式去實(shí)現(xiàn)厘惦!還是以代碼來(lái)說(shuō)明:
1、 新添加一個(gè)能夠記錄日志的代理類(想來(lái)沒有任何難度哩簿、注意實(shí)現(xiàn)了RunAble接口)——RunAbleLogProxy代碼:

package com.mmb.proxy;
public class ComplexClient {
public static void main(String[] args) {
    RunAbleTimeProxy runAbleTimeProxy = new RunAbleTimeProxy(new Dog());
    RunAbleLogProxy runAbleLogProxy = new RunAbleLogProxy(new Dog());
    runAbleLogProxy.running();
    runAbleTimeProxy.running();

    System.out.println("---------------");

    RunAbleLogProxy runAbleLogProxy1 = new RunAbleLogProxy(new Dog());
    RunAbleTimeProxy runAbleTimeProxy1 = new RunAbleTimeProxy(runAbleLogProxy1);
    runAbleTimeProxy1.running();

    System.out.println("========================");

    RunAbleTimeProxy runAbleTimeProxy2 = new RunAbleTimeProxy(new Dog());
    RunAbleLogProxy runAbleLogProxy2 = new RunAbleLogProxy(runAbleTimeProxy2);

    runAbleLogProxy2.running();
}
}

結(jié)果:

log is start 
Dog is running
log is end 
start time is 1433257548692
Dog is running
end time is 1433257549486
it takes 794 ms
---------------
start time is 1433257549486
log is start 
Dog is running
log is end 
end time is 1433257549802
it takes 316 ms
========================
log is start 
start time is 1433257549802
Dog is running
end time is 1433257549980
it takes 178 ms
log is end 

4宵蕉、繼承與聚合

留心的可以發(fā)現(xiàn)酝静、上面的靜態(tài)代理是一步步從類的繼承走向聚合的。首先是通過(guò)繼承來(lái)實(shí)現(xiàn)單一類的代理羡玛、這樣的代理形入、一個(gè)代理類只能代理一個(gè)類或者其父類。如果想代理別的類缝左、或者對(duì)同一類實(shí)現(xiàn)不同的代理亿遂、那就要另造代理類、如果需要代理的類特別多渺杉、則隨之衍生的代理類則無(wú)限的膨脹下去蛇数、簡(jiǎn)稱——類爆炸。這樣的話我們基本看不到他們的可取之處是越。設(shè)計(jì)的不合理可以定位與對(duì)Java多態(tài)的沒有充分利用耳舅。
當(dāng)我們使用聚合的時(shí)候、發(fā)現(xiàn)會(huì)靈活的太多倚评、最起碼進(jìn)一步解決了繼承所帶來(lái)的類爆炸的問(wèn)題(當(dāng)然沒有完全解決浦徊、對(duì)于不同的功能還是要我們?nèi)?shí)現(xiàn)不同的代理類)、代理?yè)碛斜淮眍惖母割愐锰煳唷⑦@樣代理可以代理代理類盔性、這種隨意的組合無(wú)疑讓我們方便很多!這是繼承所不能帶給我們的優(yōu)勢(shì)呢岗。同時(shí)從這里可以看出一點(diǎn):從接口出發(fā)的優(yōu)勢(shì)冕香!所以我們?cè)谟迷S多框架的時(shí)候、他會(huì)強(qiáng)制要求我們提供接口后豫、然后再提供他的實(shí)現(xiàn)類悉尾、就是為了更強(qiáng)的靈活性和可擴(kuò)展性!說(shuō)到底這就是一種抽象挫酿、多態(tài)的應(yīng)用构眯!

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

1早龟、動(dòng)態(tài)代理的產(chǎn)生

通過(guò)靜態(tài)處理之后惫霸、我們發(fā)現(xiàn)現(xiàn)實(shí)與理想更進(jìn)一步了。最起碼上面的看起來(lái)并不是需要寫那么多的類了拄衰。但是還是要避免不了的去寫不同的類的代理它褪、不同功能的代理。那么有沒有可能使用一個(gè)類來(lái)完成上面的所有功能的呢翘悉?
動(dòng)態(tài)代理茫打!動(dòng)態(tài)代理可以對(duì)任意的對(duì)象、任意的接口的方法、實(shí)現(xiàn)任意的代理老赤!我們不必關(guān)心轮洋、也關(guān)心不了代理內(nèi)部的實(shí)現(xiàn)、只要按照代理類的要求來(lái)使用他抬旺、就能實(shí)現(xiàn)上面的功能弊予。當(dāng)然、孤木不成林开财、我們需要按照他的要求來(lái)實(shí)現(xiàn)具有自己指定功能的類汉柒、以及被代理類。

2责鳍、動(dòng)態(tài)代理的實(shí)現(xiàn)

a)既然我們的目標(biāo)是對(duì)任意對(duì)象碾褂、任意接口的方法、實(shí)現(xiàn)任意的代理历葛、顯然要使用的是一個(gè)高度抽象的接口正塌、或者類來(lái)構(gòu)建骨架。然后在使用時(shí)傳入具體的實(shí)現(xiàn)類的對(duì)象恤溶。
b)開始的模型從簡(jiǎn)單的開始乓诽、就為一個(gè)Bird生成一個(gè)動(dòng)態(tài)代理。保留Bird類和FlyAble接口咒程、接下來(lái)就圍繞如何使用動(dòng)態(tài)代理來(lái)生成Bird的代理類鸠天。
c)既然是需要有任意性、那么就先定義一個(gè)所有代理類必須實(shí)現(xiàn)的接口InvocationHandler孵坚、使得代理類具有任意性粮宛、并且聲明一個(gè)方法invoke(Object o, Method m)、用于調(diào)用實(shí)現(xiàn)類中的此方法來(lái)實(shí)現(xiàn)代理卖宠。InvocationHandler接口:

package com.mmb.designPattern;
import java.lang.reflect.Method;

public interface InvocationHandler {
//    此方法是在Proxy中真正被執(zhí)行的,是核心
//    o是被帶理的對(duì)象忧饭,m是被執(zhí)行的方法

public void invoke(Object o ,Method m);
}

d)InvocationHandler的一個(gè)實(shí)現(xiàn)子類:TimeHandler(它不再是某一具體類的時(shí)間代理扛伍、而是Object):

package com.mmb.designPattern;

import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler {
//被代理對(duì)象
public Object target;
public TimeHandler(Object o)
{
    this.target = o;
}
/**
 * 細(xì)心的可以發(fā)現(xiàn)第一個(gè)參數(shù)Object、并沒有使用词裤。
 * 只是在這里沒有使用刺洒、我們可以按照自己的需求、吼砂、
 * 傳入一個(gè)需要借助的Object來(lái)實(shí)現(xiàn)特定的功能逆航。
 * 此方法會(huì)在Proxy中生成的代理類$Proxy1被真正的執(zhí)行、Object會(huì)傳this渔肩、也就是$Proxy1!
 */
@Override
public void invoke(Object o, Method m) {
    long start = System.currentTimeMillis();
    System.out.println("start time is " + start);
    System.out.println(o.getClass().getName());
    try{
        m.invoke(target);
    }
    catch (Exception e)
    {
        e.printStackTrace();;
    }
    long end = System.currentTimeMillis();
    System.out.println("end time is " + end);
    System.out.println("it takes " + (end-start) +" ms");
}
}

因俐、e)接下來(lái)就是核心的Proxy!Proxy只有一個(gè)功能——為我們產(chǎn)生代理類!當(dāng)然需要條件抹剩、為誰(shuí)產(chǎn)生代理類(包括他的所有方法)撑帖?產(chǎn)生什么樣的代理類?這個(gè)類當(dāng)我們完成之后澳眷、就不必再修改胡嘿。就是因?yàn)樗娜我庑裕‘?dāng)然這里面使用的點(diǎn)反射的東西钳踊、但是也沒有多少衷敌、看懂不難。
f)主要實(shí)現(xiàn)思路:
i拓瞪、將所有方法代碼拼接成字符串逢享、
ii、 將生成代理類的代碼拼接成字符串(包含所有方法拼接成的字符串)吴藻、iii瞒爬、將此字符串寫入文件中、使用JavaComplier對(duì)齊進(jìn)行編譯沟堡、
v侧但、load進(jìn)內(nèi)存供我們使用。返回代理實(shí)例航罗。
Proxy代碼:

package com.mmb.designPattern;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

/**
  • 為所有的類生成指定的代理類禀横。

  • 簡(jiǎn)單起見僅僅考慮沒有返回值沒有參數(shù)的方法的代理。

  • @author mmb

  • */
    public class Proxy {
    public static Object newInstance(Class interfaceA, InvocationHandler h) throws Exception {

     String methodStr = "";
     String rt = "\r\n";
     Method[] methods = interfaceA.getMethods();
     for (Method m : methods)
     {
         methodStr = "@Override" + rt +
                 "public void " + m.getName() + "(){" + rt +
                 "    try {" + rt +
                 "        Method md = " + interfaceA.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
                 "        h.invoke(this, md);" + rt +
                 "    }catch(Exception e) {e.printStackTrace();}" + rt +
                 "}";
     }
     String src =  "package com.mmb.designPattern;" + rt +
             "import java.lang.reflect.Method;" + rt +
             "public class $Proxy1 implements " + interfaceA.getName() + "{" + rt +
             "   com.mmb.designPattern.InvocationHandler h;" + rt +
             "   public $Proxy1(InvocationHandler h){" + rt +
             "       this.h = h;" + rt +
             "   }" + rt +
             "   "+methodStr +
             "}";
    
     String fileName = "C:\\WorkPlace\\DesignPattern\\src\\com\\mmb\\designPattern\\$Proxy1.java";
     File f = new File(fileName);
     FileWriter fw = new FileWriter(f);
     fw.write(src);
     fw.flush();
     fw.close();
    
     //compile the proxy class
     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
     StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
     Iterable units = fileMgr.getJavaFileObjects(fileName);
     JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
     t.call();
     fileMgr.close();
    
     //load into memory and create an instance
     URL[] urls = new URL[]{new URL("file:/" + "C:\\WorkPlace\\DesignPattern\\src")};
     URLClassLoader ul = new URLClassLoader(urls);
     Class c = ul.loadClass("com.mmb.designPattern.$Proxy1");
     Constructor ctr = c.getConstructor(InvocationHandler.class);
     Object m = ctr.newInstance(h);
     return m;
    
      }
    
     public static void main(String[] args) throws  Exception{
    
     Proxy proxy = new Proxy();
     Car car = new Car();
     TimeHandler timeHandler = new TimeHandler(car);
         Object o = Proxy.newInstance(RunAble.class, timeHandler);
     System.out.println(o);
     }
    }
    

生成的代理類 $Proxy1

package com.mmb.designPattern;
import java.lang.reflect.Method;
public class $Proxy1 implements
com.mmb.designPattern.RunAble{
 com.mmb.designPattern.InvocationHandler h;
   public $Proxy1(InvocationHandler h){
   this.h = h;
   }
   @Override
 public void running(){
try {
    Method md = com.mmb.designPattern.RunAble.class.getMethod("running");
    h.invoke(this, md);
}catch(Exception e) {e.printStackTrace();}
}}

五:CGLIB

spring的AOP主要是由動(dòng)態(tài)代理和CGLIB來(lái)完成代理粥血。

1柏锄、CGLIB:是針對(duì)類生成代理,針對(duì)指定的類生成一個(gè)子類复亏,覆蓋里面的方法趾娃,所以指定的類不能是final包括方法。
2:如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口缔御,默認(rèn)情況下會(huì)采用JDK的動(dòng)態(tài)代理實(shí)現(xiàn)AOP
3:目標(biāo)對(duì)象實(shí)現(xiàn)了接口抬闷,可以強(qiáng)制使用CGLIB實(shí)現(xiàn)AOP
4:如目標(biāo)對(duì)象沒有實(shí)現(xiàn)接口,必須采用CGLIB庫(kù)耕突,spirng會(huì)自動(dòng)在JDK動(dòng)態(tài)代理和CGLIB之間轉(zhuǎn)換

六:總結(jié)補(bǔ)充

1笤成、總結(jié)

代理到這里就告一段落了、從問(wèn)題的產(chǎn)生眷茁、到一步步的解決炕泳、優(yōu)化。從繼承式的靜態(tài)代理到聚合式的靜態(tài)代理上祈、從靜態(tài)代理到動(dòng)態(tài)代理培遵、逐漸的揭示了代理的功能與實(shí)現(xiàn)方式浙芙。當(dāng)一個(gè)代理類被創(chuàng)建好之后、我們就不必再關(guān)心他的信息荤懂、包括如何實(shí)現(xiàn)茁裙、具體在哪里等等、所要知道的就是如何使用即可节仿。
我們完全可以通過(guò)配置文件來(lái)指定我們想要使用的代理類晤锥。這點(diǎn)是不是讓你想到了spring的AOP?沒錯(cuò)廊宪、spring的AOP是動(dòng)態(tài)代理的一種應(yīng)用矾瘾、而不是動(dòng)態(tài)代理是AOP的一種應(yīng)用、別弄混了箭启。
還有點(diǎn)題外話壕翩、spring控制的事務(wù)是在什么時(shí)候開啟的?是在調(diào)用Dao層開啟的還是在調(diào)用Service層還是Action層傅寡?答案:一個(gè)Service層有可能調(diào)用多個(gè)Dao放妈、所以是在調(diào)用Service層方法開始、方法執(zhí)行完之后結(jié)束荐操、根據(jù)結(jié)果來(lái)判斷是提交還是回滾芜抒。

以上內(nèi)容:嚴(yán)重參考 http://blog.csdn.net/crave_shy/article/details/21000887
后面是我自己擴(kuò)充的一些知識(shí)

七、JDK的Proxy類的使用方法

先發(fā)布了托启,這部分宅倒,等我學(xué)明白了再寫

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市屯耸,隨后出現(xiàn)的幾起案子拐迁,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)饶辙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)可霎,“玉大人科乎,你說(shuō)我怎么就攤上這事∏澳穑” “怎么了患雏?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)罢维。 經(jīng)常有香客問(wèn)我淹仑,道長(zhǎng)丙挽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任匀借,我火速辦了婚禮颜阐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吓肋。我一直安慰自己凳怨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布是鬼。 她就那樣靜靜地躺著肤舞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪均蜜。 梳的紋絲不亂的頭發(fā)上李剖,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音囤耳,去河邊找鬼篙顺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛充择,可吹牛的內(nèi)容都是我干的德玫。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼聪铺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼化焕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起铃剔,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤撒桨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后键兜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凤类,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年普气,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谜疤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡现诀,死狀恐怖夷磕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情仔沿,我是刑警寧澤坐桩,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站封锉,受9級(jí)特大地震影響绵跷,放射性物質(zhì)發(fā)生泄漏膘螟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一碾局、第九天 我趴在偏房一處隱蔽的房頂上張望荆残。 院中可真熱鬧,春花似錦净当、人聲如沸内斯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嘿期。三九已至,卻和暖如春埋合,著一層夾襖步出監(jiān)牢的瞬間备徐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工甚颂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜜猾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓振诬,卻偏偏與公主長(zhǎng)得像蹭睡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赶么,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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

  • title: Jdk動(dòng)態(tài)代理原理解析 tags:代理 categories:筆記 date: 2017-06-14...
    行徑行閱讀 19,247評(píng)論 3 36
  • 整體Retrofit內(nèi)容如下: 1肩豁、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李頭閱讀 3,232評(píng)論 2 10
  • 生活中不斷被人侵犯 卻總是合理化對(duì)方也是為了我好 我怎么可以對(duì)她表達(dá)憤怒呢 事實(shí)是我真的受到傷害了 我有憤怒 因?yàn)?..
    竺子閱讀 252評(píng)論 0 0
  • 詩(shī)說(shuō)三月?lián)P州好辫呻,煙花天地楊花蕾清钥。 可知孔明洗馬處,長(zhǎng)有梅子伴年歲放闺。 祭日重回鴛鴦水祟昭,雙樹婆娑載風(fēng)飛。 平洲小艇過(guò)江...
    步紅塵閱讀 447評(píng)論 1 3
  • 我才15歲,但是我覺得我遇到的這些事不算少匾寝。 我有一個(gè)朋友搬葬,上一次大晚上的他給我發(fā)信息說(shuō)她好委屈。 她有個(gè)朋友的爸...
    宇宙最酷丁慧玲閱讀 206評(píng)論 0 0