Retrofit2原理分析

一.Retrofit是什么

      Retrofit是square开源的一个Restful的http网络请求框架的封装。
      网络请求的工作本质是okhttp完成,而Retrofit仅负责网络请求接口的封装。开发者只需要定义接口就可以了,Retrofit提供了注解可以表示该接口请求的请求方式、参数、url等。定义好了接口以后,在调用该远程接口的时候直接使用该接口就好像通过RPC方式使用本地类一样方便。


image.png

      App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数、Header、Url等信息,然后有OkHttp完成后续的请求操作。
      在服务端返回数据之后,OkHttp将原始的数据结果交给Retrofit,Retrofit根据用户的需求对结果进行解析。
      Retrofit的设计任务如下:

请求前 结果返回
1.统一配置网络请求头
2.一致适配请求request
1.线程切换
2.数据适配

      下面通过一个实例来看一下使用Retrofit的工作流程及分析一下其工作原理:

二.具体实例

a.定义接口
public interface RetrofitApi {

    @GET("weather_mini")
    Call<WeatherInfo> getWeatherInfo(@Query("city") String city);

    @GET("HPImageArchive.aspx")
    Observable<ImageBean> getImage(@Query("format") String format, @Query("idx") int idx, @Query("n") int n);
}
b.Retrofit创建
Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://cn.bing.com/")
             //设置使用Gson解析(可将得到的Json串转换为与其结构相符的对应ImageBean类)
            .addConverterFactory(GsonConverterFactory.create())
             //支持RxJava2[可以不设置该参数,则使用默认的]
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();
c.创建接口对象
RetrofitApi request = retrofit.create(RetrofitApi.class);
d.方法调用
//1.默认Call调用
Call<WeatherInfo> call = request.getWeatherInfo("北京");
call.enqueue(new Callback<WeatherInfo>() {
        @Override
        public void onResponse(Call<WeatherInfo> call, Response<WeatherInfo> response) {
            Log.e("Seven", "use call to get weather info is: " + response.body().toString());
        }

        @Override
        public void onFailure(Call<WeatherInfo> call, Throwable t) {
        }
});

//2.结合RxJava2调用[即设置了addCallAdapterFactory(RxJava2CallAdapterFactory.create())]
Observable<ImageBean> observable = request.getImage("js", step, 1);
observable.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<ImageBean>() {
                ......

                    @Override
                    public void onNext(ImageBean imageBean) {
                        List<ImageBean.ImagesBean> imagesBeans = imageBean.getImages();
                        ImageBean.ImagesBean imagesBean = imagesBeans.get(0);
                        String url = ImageBean.ImagesBean.BASE_URL + imagesBean.getUrl();
                        String des = imagesBean.getCopyright();
                        imageUrl.setValue(url);
                        imageDescription.setValue(des);
                    }
                    ......
            });

三.原理分析

      通过上面的实例可以看到,先是创建了Retrofit并对其进行配置,采用了建造者模式,然后通过Retrofit去创建接口对象,最后通过接口对象来调用方法,那么下面就一步一步来分析其工作原理。

a.Retrofit创建

      Retrofit创建采用的是建造者模式,这里直接跳到最后build()方法:

public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //创建callFactory,就是一个okhttp3.OkHttpClient实例
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //创建callbackExecutor,最终返回的是Android Platform的MainThreadExecutor
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

     //创建默认的CallAdapter.Factory
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      //获取到Converter.Factory,addConverterFactory(GsonConverterFactory.create())已经执行了
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
      
      //最后将各个参数放在一起创建了一个Retrofit实例
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

      从上述方法可以看到,主要工作如下:
      baseUrl:网络请求的url地址;
      callFactory:网络请求工厂,此处创建一个OkHttpClient()实例,后面进行网络请求会用到该实例,网络请求逻辑是在okhttp里面;
      callbackExecutor:回调方法执行器,用来线程切换;
      adapterFactories:网络请求适配器工厂的集合,会创建默认的CallAdapter.Factory,供Call方式来使用,若配置了addCallAdapterFactory(RxJava2CallAdapterFactory.create()),优先使用Observable;
      converterFactories:数据转换器工厂的集合,配置了addConverterFactory(GsonConverterFactory.create()),使用Gson进行解析数据;

b.通过Retrofit创建接口对象

      接口对象是通过Retrofit.create(xx.class) 来创建的,一起看一下源码:

public <T> T create(final Class<T> service) {
    ......
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          @Override public Object invoke(Object proxy, Method method, Object... args)
              throws Throwable {
            .....
            //创建ServiceMethod对象
            ServiceMethod serviceMethod = loadServiceMethod(method);
            //创建OkHttpCall对象
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //返回结果,即Call或Observable
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

      create()内通过动态代理生成一个代理类对象,具体来说就是通过Proxy.newProxyInstance()来创建的。此处使用的是Java动态代理创建的,可以参考Java动态代理学习,通过代理类调用接口方法时会回调invoke()方法,看一下invoke()方法内都执行了哪些逻辑:
      1.创建ServiceMethod实例

ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      //先从cache里面取,如果已经存在了,就不去创建,即方法执行过一次,就不会重新创建了
      result = serviceMethodCache.get(method);
      if (result == null) {
        //通过构造者模式来创建ServiceMethod实例
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

      由于ServiceMethod在创建时,会将App层执行的method作为参数传入,从而会用到反射来获取Method的请求参数等,反射会消耗性能,因此对ServiceMethod做了缓存,不会每次都去创建进行反射。

public ServiceMethod build() {
      //创建callAdapter,在invoke()方法最后会用到,如果Retrofit配置了RxJava2转换器,那这里就是RxJava2CallAdapter
      callAdapter = createCallAdapter();
      .....
      //获取response转换器
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
        //解析接口内方法的注解,可以获取到Http请求方式,请求体,url等信息
        parseMethodAnnotation(annotation);
      }

      //解析当前方法的参数
     int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      ......
      ......
      return new ServiceMethod<>(this);
    }

private CallAdapter<?> createCallAdapter() {
      ......
      Annotation[] annotations = method.getAnnotations();
      try {
        //此处是重点,会调用retrofit内的callAdapter方法
        return retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }

      ServiceMethod在创建时,主要工作如下:
      callAdapter:明确正确的callAdapter;
      responseType:确定Call接口的返回值类型;
      responseConverter:明确对应的数据转换器;
      parameterHandlers:对接口中的注解参数进行解析配置;

      2.OkHttpCall
      OkHttpCall继承于Retrofit2.Call,内部主要对okhttp3一系列操作的封装:

final class OkHttpCall<T> implements Call<T> {
    OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
    }
    ......
    @Override public synchronized Request request() {}
    @Override public void enqueue(final Callback<T> callback) {}
    @Override public Response<T> execute() throws IOException {}
    .....
}

      3.CallAdapter.adapt(okHttpCall)
      在invoke()方法中,最后会return serviceMethod.callAdapter.adapt(okHttpCall);,上面有提到过,这一步的作用是返回一个Retrofit2.Call或者Observable。
      CallAdapter是一个接口对象,因此需要找到它的实现类。在Retrofit创建的时候,会创建默认的CallAdapter.Factory,返回Retrofit2.Call;如果配置了addCallAdapterFactory(RxJava2CallAdapterFactory.create()),会优先将接口方法返回Observable。
①默认返回Call
      创建Retrofit时,配置流程如下:
      ------>Retrofit.build()
            ------>platform.defaultCallAdapterFactory(callbackExecutor)
                  ------>new ExecutorCallAdapterFactory(callbackExecutor)
      调用接口方法时,ServiceMethod创建CallAdapter流程如下:
      ------>SeviceMethod.createCallAdapter()
            ------>Retrofit.callAdapter(returnType, annotations)
                  ------>Retrofit.nextCallAdapter()
                        ------>adapterFactories.get(i).get(returnType, annotations, this);
      通过adapterFactories.get(i).get(returnType, annotations, this),调用get()方法,最终会调用ExecutorCallAdapterFactory里面的get()方法:

//ExecutorCallAdapterFactory.java
@Override
  public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

      通过以上逻辑可以看到,在调用get()后,会返回CallAdapter实例,然后再调用adapt()方法后,会返回new ExecutorCallbackCall<>(callbackExecutor, call),是Call接口的实现类。

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
}

      ExecutorCallbackCall的参数callbackExecutor是通过Android platform返回的,持有主线程的Handler,执行execute()后,会在主线程内执行。

//Platform.java
static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

      ExecutorCallbackCall的参数call就是OkHttpCall实例,后面请求的时候会用到。
      以上分析完成,在通过RetrofitApi调用其接口后,会返回Call实例。
②配置RxJava2返回Observable
      在创建Retrofit时,通过配置addCallAdapterFactory(RxJava2CallAdapterFactory.create())就在callAdapterFactories列表中加入了RxJava2CallAdapterFactory,执行get()方法看一下源码实现逻辑:

//RxJava2CallAdapterFactory.java
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
  @Override
  public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    ......
    boolean isResult = false;
    boolean isBody = false;
    ......
    ......
    return new RxJava2CallAdapter(responseType, scheduler, isResult, isBody, isFlowable,
        isSingle, isMaybe, false);
}

      在get()方法会创建RxJava2CallAdapter实例,看一下源码实现逻辑:

//RxJava2CallAdapter.java
final class RxJava2CallAdapter implements CallAdapter<Object> {
    .....
    @Override public <R> Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = new CallObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      //最终返回的Observable是responseObservable,即CallObservable
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }
}

      然后调用adapt()方法后,会返回Observable,CallObservable内的参数call就是OkHttpCall实例,后面请求的时候会用到。
      以上分析完成,在通过RetrofitApi调用其接口后,会返回Observable实例。
      用一张图总结一下返回Call或Observable流程

image.png

c.方法调用

      1.Call.enqueue()
      上面的实例中可以看到,Call对象是通过enqueue()或者execute()发起请求的,而这个Call对象实际上是ExecutorCallbackCall的实例,前面已经分析过,在看一下ExecutorCallbackCall的enqueue方法:

@Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

      当外部调用enqueue()时,最终调用的就是delegate.enqueue()方法,delegate是OkHttpCall,一起看一下OkHttpCall.java实现逻辑:

final class OkHttpCall<T> implements Call<T> {
    private final ServiceMethod<T> serviceMethod;
    private final Object[] args;
    ......
    private okhttp3.Call rawCall;

    //invoke()方法内,创建OkHttpCall是传入serviceMethod及args
    OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
    }

    ......
@Override public void enqueue(final Callback<T> callback) {
    .....

    okhttp3.Call call;
    .......
    //创建okhttp3.Call对象
    call = rawCall = createRawCall();
    ......
    ......
    //调用okhttp3内的逻辑
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          //得到response,最终调用到SeviceMethoad内的toResponse()方法
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        //回调方法
        callSuccess(response);
      }
      ......
      private void callSuccess(Response<T> response) {
          try {
              //回调ExecutorCallbackCall内的onResponse()
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
        });
    }
    .......
    private okhttp3.Call createRawCall() throws IOException {
        //调用serviceMethod的toRequest()方法,将其组装成http请求的request
        Request request = serviceMethod.toRequest(args);
        //serviceMethod.callFactory对应的是okhttpClient实例,即调用okhttpClient的newCall方法
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);
        return call;
    }
    .......
}

      从上面可以看到,在执行enqueue()时,会执行createRawCall(),该方法内部用到了SeviceMethod的toRequest()方法,将方法内的请求参数组装成http request,然后通过newCall创建okhttp3.call(),再调用okhttp3.call()的enqueue()方法,后续就由okhttp来进行网络请求处理了。
      在得到结果后,用到了SeviceMethod的toResponse()方法,将请求结果转为为自定义的类。结果返回后会执行callbackExecutor.execute(),前面讲到,callbackExecutor.execute()是在主线程执行,因此,enqueue后返回的结果是在主线程。
      以上就是app端在调用enqueue后的执行流程。
      2.Observable.subscribe()
      前面分析过,Observable是在RxJava2CallAdapter内部的adapt()方法返回的,最终返回的是CallObservable,当执行CallObservable.subscribe()后,从RxJava2的源码RxJava学习可以知道,每个Observable都会去调用subscribeActual(),看一下CallObservable的逻辑:

final class CallObservable<T> extends Observable<Response<T>> {
  ......

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    ......

    boolean terminated = false;
    try {
      //直接获取到response
      Response<T> response = call.execute();
      if (!call.isCanceled()) {
        //回调onNext()
        observer.onNext(response);
      }
      if (!call.isCanceled()) {
        terminated = true;
        observer.onComplete();
      }
    }
    ......
    }
}

      通过call.execute()去发起网络请求,看一下OkHttpCall这个类的另外一个方法execute():

@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;
    ......
    call = rawCall = createRawCall();
    .....
    //直接调用okhttp3的execute()去获取response,然后进行转换返回
    return parseResponse(call.execute());
  }

      可以看到,请求方式跟上面的是类似的,一个是同步,一个是异步,得到转换后的response后通过observer.onNext()回调。
      至此,Retrofit2请求的原理分析已经结束了。主要涉及到Retrofit.create()用到的动态代理,网络请求的OkHttp以及与RxJava2适配等。
      用一张图总结一下请求流程

image.png

四.总结

a.使用Retrofit流程如下:

      1、定义请求接口;
      2、通过建造者模式创建一个Retrofit实例,对并Retrofit进行相关参数配置;
      3、通过Retrofit对象的creat()方法创建一个代理对象;
      4、当调用接口方法时,都会调用动态代理的invoke()方法;invoke()内部做了3件事情:
            a. 对method进行解析,生成ServiceMethod对象并缓存起来,下次调用就不需要解析了;
            b. 将原始的okhttp3.call[okhttp3]封装成OkHttpCall[retrofit2];
            c. 通过CallAdapter转换成Call对象或者Observable对象;
      5、如果返回Call对象,调用execute或者enqueue方法去做请求,最终在onResponse()里面进行请求结果逻辑处理;如果返回Observable对象,则通过Rxjava2最终在onNext()里面进行请求结果逻辑处理。

b.Retrofit封装的点:

      1.Build模式创建网络请求基本配置;
      2.用注解来排列组合成网络请求,以不变应万变;
      3.统一提供Gson解析,提供了可复用、易扩展的数据解析方案;
      4.自定义Executor(Handler)完成线程的切换;

c.Retrofit用到的设计模式

      1.Retrofit实例使用建造者模式通过Builder类构建,当构造函数的参数大于4个,且存在可选参数的时候就可以使用建造者设计模式;
      2.Retrofit创建的CallFactory,使用工厂方法设计模式,此处只支持OkHttp;
      3.整个Retrofit采用的是外观模式,统一的调用创建网络请求接口实例和网络请求参数配置的方法;
      4.Retrofit里面使用了动态代理模式来创建网络请求接口实例,这个是retrofit对用户使用来说最大的复用,其他的代码都是为了支撑这个动态代理给用户带来便捷性的;
      5.使用了策略模式对serviceMethod对象进行网络请求参数配置,即通过解析网络请求接口方法的参数、返回值和注解类型,从Retrofit对象中获取对应的网络的url地址,网络请求执行器、网络请求适配器和数据转换器;
      6.ExecutorCallbackCall使用装饰者模式来封装callbackExecutor,用于完成线程的切换;
      7.ExecutorCallbackCall使用静态代理模式代理了call进行网络请求,真正的网络请求是由okhttpcall执行,然而okhttpcall不是自己执行,它是okhttp提供call给外界(retrofit)使用的唯一门户,此处是门面模式
      8.ExecutorCallbackCall的初始化是在ExecutorCallAdapterFactory里面通过适配器模式创建的,CallAdapter采用了适配器模式为创建访问call接口提供服务,默认ExecutorCallAdapterFactory将okhttp3.call转换为Retrofit中的Call,如果使用Rxjava,则将okhttp3.call转换为Observable;
      9.当使用了Rxjava时,app层注册observer,即观察者模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容