Spring AOP(六)細(xì)究 JdkDynamicAopProxy 類

本文來分析 Spring 中 JdkDynamicAopProxy 代理對(duì)象的生成 getProxy() 方法和攔截增強(qiáng) invoke 方法的相關(guān)處理邏輯。

上文我們研究過了 PointcutAdviceAdvisor)接口以及它們?cè)?Spring AOP 代理中的作用永品,并利用幾個(gè) Demo 演示了其相關(guān)關(guān)系辽故。

為了方便閱讀,把上文中的 ProxyFactoryDemo 類代碼再次貼出來腐碱。

public class ProxyFactoryDemo {

    public static void main(String[] args) {
        // 1. 構(gòu)造目標(biāo)對(duì)象
        Cat catTarget = new Cat();

        // 2. 通過目標(biāo)對(duì)象誊垢,構(gòu)造 ProxyFactory 對(duì)象
        ProxyFactory factory = new ProxyFactory(catTarget);

        // 添加一個(gè)方法攔截器
        factory.addAdvice(new MyMethodInterceptor());

        // 3. 根據(jù)目標(biāo)對(duì)象生成代理對(duì)象
        Object proxy = factory.getProxy();

        Animal cat = (Animal) proxy;
        cat.eat();
    }
}

源碼分析

首先掉弛,我們從 ProxyFactory 類的 getProxy() 方法開始分析。

public Object getProxy() {
  return createAopProxy().getProxy();
}

createAopProxy()ProxyFactory 父類 ProxyCreatorSupport 中的方法的主要是根據(jù)當(dāng)前的 config 信息判斷是生成 JDK 動(dòng)態(tài)代理還是 CGLIB 動(dòng)態(tài)代理喂走。

protected final synchronized AopProxy createAopProxy() {
  if (!this.active) {
    activate();
  }
  // 1. 獲取 AopProxyFactory 工廠殃饿,用來創(chuàng)建 AopProxy 對(duì)象
  // 注意 createAopProxy 的參數(shù) this,this 就是在 ProxyFactoryDemo 中定義的 ProxyFactory 對(duì)象芋肠。
  return getAopProxyFactory().createAopProxy(this);
}

/*
 *  子類構(gòu)造函數(shù)中如果不顯示調(diào)用父類的構(gòu)造函數(shù)乎芳,則會(huì)自動(dòng)調(diào)用父類的無參構(gòu)造函數(shù)
 *  所以,ProxyCreatorSupport() 方法會(huì)在 ProxyFactory factory = new ProxyFactory(catTarget); 調(diào)用時(shí)被調(diào)用
 */
public ProxyCreatorSupport() {
  this.aopProxyFactory = new DefaultAopProxyFactory();
}

public AopProxyFactory getAopProxyFactory() {
  // DefaultAopProxyFactory 對(duì)象
  return this.aopProxyFactory;
}

下面我們繼續(xù)來看 DefaultAopProxyFactory 類中的 createAopProxy 方法帖池。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  // config.isOptimize() 這個(gè)屬性沒有研究過
  // 滿足下面三個(gè)條件的任意一個(gè)
  // 1. 如果 optimize 屬性為 ture 
  // 2. 或者 proxyTargetClass 屬性為 ture
  // 3. 被代理類沒有可代理的接口
  if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    Class<?> targetClass = config.getTargetClass();
    if (targetClass == null) {
      throw new AopConfigException("TargetSource cannot determine target class: " +
          "Either an interface or a target is required for proxy creation.");
    }
    // 如果被代理類的類型是接口奈惑,或者被代理類是 JDK 動(dòng)態(tài)代理生成的代理類,則使用 JDK 動(dòng)態(tài)代理
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
      return new JdkDynamicAopProxy(config);
    }
    
    // 使用 CGLIB 動(dòng)態(tài)代理
    return new ObjenesisCglibAopProxy(config);
  }
  else {
    //  使用 JDK 動(dòng)態(tài)代理
    return new JdkDynamicAopProxy(config);
  }
}

ObjenesisCglibAopProxy 類在下一篇文章講解睡汹,先來看 JdkDynamicAopProxy 類的 getProxy() 方法肴甸。

public Object getProxy() {
  return getProxy(ClassUtils.getDefaultClassLoader());
}

public Object getProxy(@Nullable ClassLoader classLoader) {
  if (logger.isTraceEnabled()) {
    logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
  }
  // 得到所有需要代理的接口
  Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
  // 查找被代理的接口中是否包含 equals 和 hashCode 方法,如果有囚巴,則在代理類中進(jìn)行相應(yīng)的標(biāo)記原在,
  // 從而在 invoke 方法中直接調(diào)用相關(guān)的方法,避免遞歸調(diào)用導(dǎo)致棧溢出
  findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  
  // 這里就是我們熟悉的 Proxy.newProxyInstance 方法了彤叉,用來生成 JDK 動(dòng)態(tài)代理對(duì)象庶柿。
  return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
  // advised 就是在 ProxyFactoryDemo 中定義的 ProxyFactory 對(duì)象。
  this.advised = config;
}

AopProxyUtils 類中的的 completeProxiedInterfaces() 方法需要講解下秽浇。

/**
 * 返回要為給定 AOP 配置代理的完整接口集浮庐。
 *   始終添加 SpringProxy 接口
 *   如果 opaque 標(biāo)記為 false,則始終添加 Advised 接口
 * @param advised 代理配置
 * @param decoratingProxy 為 ture 則添加 DecoratingProxy 接口
 */
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
  // 1. 獲取到所有需要被代理的接口
  Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
 
  // 如果被代理的接口集合中沒有 SpringProxy 接口柬焕,則需要添加 SpringProxy 接口到被代理集合集合中
  boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
  
  // 如果 opaque 為 false(默認(rèn)是 false)审残,且被代理的接口集合中沒有 Advised 接口,則需要添加 Advised 接口到被代理集合集合中
  boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
  
  // decoratingProxy 為 ture击喂,且被代理的接口集合中沒有 DecoratingProxy 接口维苔,則需要添加 DecoratingProxy 接口到被代理集合集合中
  boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
  
  // 省略添加邏輯...
  
  return proxiedInterfaces;
}

由此,我們就知道了 JdkDynamicAopProxy 代理類的生成邏輯懂昂。

然后我們?cè)賮砜?JdkDynamicAopProxy 類的 invoke 方法介时。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  MethodInvocation invocation;
  Object oldProxy = null;
  boolean setProxyContext = false;

  TargetSource targetSource = this.advised.targetSource;
  Object target = null;

  try {
    if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
      // 不代理 equals 方法,通過 JdkDynamicAopProxy 中定義的 equals 方法進(jìn)行比較
      return equals(args[0]);
    }
    else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
      // 不代理 hashCode 方法凌彬,調(diào)用 JdkDynamicAopProxy 中定義的 hashCode 方法
      return hashCode();
    }
    else if (method.getDeclaringClass() == DecoratingProxy.class) {
      // DecoratingProxy 接口中只有 getDecoratedClass 方法沸柔,通過下面的方法實(shí)現(xiàn)其邏輯
      return AopProxyUtils.ultimateTargetClass(this.advised);
    }
    else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
        method.getDeclaringClass().isAssignableFrom(Advised.class)) {
      // opaque 為 false 才可能代理 Advised 接口
      // 如果 method 是在 Advised 中聲明的,則直接把 method 轉(zhuǎn)移到 advised 對(duì)象上調(diào)用铲敛。
      // 這樣就可以通過代理對(duì)象直接操作代理的配置褐澎,比如新增 Advisor。
      return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    }

    Object retVal;

    if (this.advised.exposeProxy) {
      // 如果需要在攔截器暴露 proxy 對(duì)象伐蒋,則把 proxy 對(duì)象添加到 ThreadLocal 中
      oldProxy = AopContext.setCurrentProxy(proxy);
      setProxyContext = true;
    }

    // 獲取目標(biāo)對(duì)象和目標(biāo)對(duì)象類型
    target = targetSource.getTarget();
    Class<?> targetClass = (target != null ? target.getClass() : null);

    // 獲取此方法的攔截器鏈工三,這個(gè)方法后面會(huì)進(jìn)行討論
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
    if (chain.isEmpty()) {
      // 如果攔截器集合為空迁酸,說明當(dāng)前 method 不需要被增強(qiáng),則通過反射直接調(diào)用目標(biāo)對(duì)象上的方法
      Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
      retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    }
    else {
      // 創(chuàng)建 ReflectiveMethodInvocation俭正,用來管理方法攔截器責(zé)任鏈
      // 類似于 【Spring AOP (四) 多重代理和責(zé)任鏈模式】 中的 MyMethodInvocationImpl
      invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
      // 通過 invocation.proceed 驅(qū)動(dòng)方法攔截器責(zé)任鏈的運(yùn)行奸鬓,并獲取到返回值。
      retVal = invocation.proceed();
    }

    // 返回 this掸读,需要替換為 proxy 對(duì)象
    Class<?> returnType = method.getReturnType();
    if (retVal != null && retVal == target &&
        returnType != Object.class && returnType.isInstance(proxy) &&
        !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
      retVal = proxy;
    }
    else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
      throw new AopInvocationException(
          "Null return value from advice does not match primitive return type for: " + method);
    }
    return retVal;
  }
  finally {
    if (setProxyContext) {
      // 把第一次調(diào)用 setCurrentProxy 返回的對(duì)象串远,重新設(shè)置到 ThreadLocal 中
      AopContext.setCurrentProxy(oldProxy);
    }
  }
}

我們接下來分析一下在 invoke 方法中值得關(guān)注的地方。

advisedgetInterceptorsAndDynamicInterceptionAdvice 方法儿惫,此方法定義在 AdvisedSupport 類中澡罚。

AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
  // 1. 定義 method 的 cacheKey,用來緩存結(jié)果
  MethodCacheKey cacheKey = new MethodCacheKey(method);
  
  // 2. 從緩存中獲取 method 的攔截器列表
  List<Object> cached = this.methodCache.get(cacheKey);
  if (cached == null) {
    // 3. 通過 DefaultAdvisorChainFactory的 getInterceptorsAndDynamicInterceptionAdvice 獲取 method 的攔截器列表
    cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
        this, method, targetClass);
    // 4. 保存 method 的攔截器列表到緩存中
    this.methodCache.put(cacheKey, cached);
  }
  return cached;
}

getInterceptorsAndDynamicInterceptionAdvice 方法中涉及 DefaultAdvisorChainFactory 類中的相關(guān)代碼清單如下所示肾请。


// 省略了方法中關(guān)于 Introduction 增強(qiáng)的處理邏輯
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Advised config, Method method, @Nullable Class<?> targetClass) {

  // // 獲取一個(gè)全局唯一的 AdvisorAdapterRegistry  對(duì)象
  AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
  // 這里的 config留搔,就是最開始定義的 ProxyFactory 對(duì)象
  // 獲取到所有的 Advisor
  Advisor[] advisors = config.getAdvisors();
  List<Object> interceptorList = new ArrayList<>(advisors.length);
  Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());

  for (Advisor advisor : advisors) {
    // 如果 advisor 是 PointcutAdvisor 類型
    if (advisor instanceof PointcutAdvisor) {
      PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
      // 如果 preFiltered 為 ture,或者目標(biāo)對(duì)象類型滿足 ClassFilter 的條件筐喳,則進(jìn)行下面的處理
      if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
        MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
        boolean match;
          // 進(jìn)行方法的靜態(tài)匹配
          match = mm.matches(method, actualClass);
        if (match) {
          // 匹配則把 advisor 中的 Advice(MethodInterceptor 是 Advice 的子接口) 添加方法攔截器列表
          MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
          if (mm.isRuntime()) {
            // 如果需要進(jìn)行方法的動(dòng)態(tài)匹配催式,則轉(zhuǎn)換為 InterceptorAndDynamicMethodMatcher 類型函喉,在 invoke 方法調(diào)用時(shí)進(jìn)行動(dòng)態(tài)匹配
            for (MethodInterceptor interceptor : interceptors) {
              interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
            }
          }
          else {
            interceptorList.addAll(Arrays.asList(interceptors));
          }
        }
      }
    }
    // 不是 PointcutAdvisor 說明沒有 Pointcut避归,則匹配所有方法
    else {
      Interceptor[] interceptors = registry.getInterceptors(advisor);
      interceptorList.addAll(Arrays.asList(interceptors));
    }
  }

  return interceptorList;
}

getInterceptorsAndDynamicInterceptionAdvice 方法中一個(gè)容易忽略的地方就是 AdvisorAdapterRegistry 接口和其 getInterceptors 方法。

GlobalAdvisorAdapterRegistry 類的代碼清單如下所示管呵。

public final class GlobalAdvisorAdapterRegistry {

    private GlobalAdvisorAdapterRegistry() {
    }


    /**
     * 保存單個(gè)實(shí)例梳毙,以便我們給請(qǐng)求它的類使用。
     */
    private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();

    public static AdvisorAdapterRegistry getInstance() {
        return instance;
    }

    static void reset() {
        instance = new DefaultAdvisorAdapterRegistry();
    }

}

DefaultAdvisorAdapterRegistry 類的代碼清單如下所示捐下。

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

    private final List<AdvisorAdapter> adapters = new ArrayList<>(3);

    /**
     * 創(chuàng)建一個(gè)新的 DefaultAdvisorAdapterRegistry账锹,注冊(cè)默認(rèn)的 AdvisorAdapter。
     */
    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }

    /**
     * 返回給定 advice 的包裝類 advisor
     *     默認(rèn)至少支持如下 Advice:
     *        org.aopalliance.intercept.MethodInterceptor
     *        org.springframework.aop.MethodBeforeAdvice
     *        org.springframework.aop.AfterReturningAdvice
     *        org.springframework.aop.ThrowsAdvice
     */
    @Override
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        // 如果 adviceObject 已經(jīng)是 Advisor 實(shí)例坷襟,直接返回
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }

        // 如果 adviceObject 不是 Advice 實(shí)例奸柬,直接拋出異常
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        if (advice instanceof MethodInterceptor) {
            // MethodInterceptor 不需要 wrap
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // 檢查 adapter 是否理解此 advice 對(duì)象? 即使用 Advisor 調(diào)用 getInterceptors 方法作為參數(shù)是否有效婴程?
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }

        // 如果上面的條件都不滿足廓奕,直接拋出異常
        throw new UnknownAdviceTypeException(advice);
    }

    @Override
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<>(3);
        Advice advice = advisor.getAdvice();

        // 1. 如果 advice 是 MethodInterceptor 實(shí)例,直接添加到攔截器列表
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }

        // 2. 如果存在 adapter可以把 advisor 轉(zhuǎn)換為 MethodInterceptor档叔,也需要添加到攔截器列表
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }

        // 攔截器列表為空桌粉,則拋出異常
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[0]);
    }

    @Override
    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }

}

我們繼續(xù)來看 AdvisorAdapter 的相關(guān)實(shí)現(xiàn)類中的 getInterceptor 方法。

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof MethodBeforeAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        // 返回 MethodInterceptor 接口實(shí)現(xiàn)類 MethodBeforeAdviceInterceptor
        return new MethodBeforeAdviceInterceptor(advice);
    }
}

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {

    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof AfterReturningAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
        // 返回 MethodInterceptor 接口實(shí)現(xiàn)類 AfterReturningAdviceInterceptor
        return new AfterReturningAdviceInterceptor(advice);
    }

}

class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {

    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof ThrowsAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        // 返回 MethodInterceptor 接口實(shí)現(xiàn)類 ThrowsAdviceInterceptor
        return new ThrowsAdviceInterceptor(advisor.getAdvice());
    }

}

最后衙四,我們需要分析一下 ReflectiveMethodInvocation 類中 proceed 的邏輯铃肯,proceed 方法驅(qū)動(dòng)責(zé)任鏈模式的運(yùn)行。

/**
 * 當(dāng)前攔截器列表索引传蹈,表示當(dāng)前已經(jīng)運(yùn)行到第幾個(gè) MethodInterceptor
 */
private int currentInterceptorIndex = -1;

public Object proceed() throws Throwable {
  //  如果攔截器列表已經(jīng)執(zhí)行完畢押逼,則調(diào)用目標(biāo)對(duì)象的目標(biāo)方法
  if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    return invokeJoinpoint();
  }

  // 獲取責(zé)任鏈中的下一個(gè) MethodInterceptor步藕,用來對(duì)目標(biāo)方法做增強(qiáng)處理
  Object interceptorOrInterceptionAdvice =
      this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    // 如果 interceptorOrInterceptionAdvice 是 InterceptorAndDynamicMethodMatcher 類型,說明需要對(duì)目標(biāo)方法進(jìn)行動(dòng)態(tài)匹配
    InterceptorAndDynamicMethodMatcher dm =
        (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
    
    // 方法動(dòng)態(tài)匹配成功挑格,才對(duì)目標(biāo)方法做增強(qiáng)處理
    if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
      return dm.interceptor.invoke(this);
    }
    else {
      // 方法動(dòng)態(tài)匹配失敗漱抓,則驅(qū)動(dòng)責(zé)任鏈向前運(yùn)行
      return proceed();
    }
  }
  else {
    // 如果目標(biāo)方法不需要?jiǎng)討B(tài)匹配,則直接調(diào)用 MethodInterceptor 的 invoke 方法恕齐,對(duì)目標(biāo)方法做增強(qiáng)處理乞娄。
    return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  }
}

至此我們可以得知,Spring AOP 代理 是由如下兩個(gè)核心接口實(shí)現(xiàn)的显歧。

  • MethodInterceptor 接口中的 invoke 方法對(duì)目標(biāo)方法做代理(增強(qiáng))處理仪或。

  • MethodInvocation 接口中的 proceed() 方法通過責(zé)任鏈模式對(duì)目標(biāo)方法做多重代理。在其實(shí)現(xiàn)類 ReflectiveMethodInvocation 中實(shí)現(xiàn)此邏輯士骤。

Spring 中的 JDK AOP 代理類 JdkDynamicAopProxy 到這里就基本說完了范删,下一篇我們講解 CGLIB AOP 代理類 ObjenesisCglibAopProxy 類。

(正文完)

擴(kuò)展閱讀

喜歡本文的朋友們拷肌,歡迎關(guān)注微信公眾號(hào)【程序員小課堂】到旦,閱讀更多精彩內(nèi)容!


程序員小課堂.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巨缘,一起剝皮案震驚了整個(gè)濱河市添忘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌若锁,老刑警劉巖搁骑,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異又固,居然都是意外死亡仲器,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門仰冠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乏冀,“玉大人,你說我怎么就攤上這事洋只×韭伲” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵木张,是天一觀的道長众辨。 經(jīng)常有香客問我,道長舷礼,這世上最難降的妖魔是什么鹃彻? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮妻献,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己囊嘉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布欢摄。 她就那樣靜靜地躺著,像睡著了一般笋粟。 火紅的嫁衣襯著肌膚如雪怀挠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天害捕,我揣著相機(jī)與錄音绿淋,去河邊找鬼。 笑死尝盼,一個(gè)胖子當(dāng)著我的面吹牛吞滞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盾沫,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼裁赠,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了赴精?” 一聲冷哼從身側(cè)響起佩捞,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎祖娘,沒想到半個(gè)月后失尖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啊奄,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渐苏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了菇夸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琼富。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖庄新,靈堂內(nèi)的尸體忽然破棺而出鞠眉,到底是詐尸還是另有隱情,我是刑警寧澤择诈,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布械蹋,位于F島的核電站,受9級(jí)特大地震影響羞芍,放射性物質(zhì)發(fā)生泄漏哗戈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一荷科、第九天 我趴在偏房一處隱蔽的房頂上張望唯咬。 院中可真熱鬧纱注,春花似錦、人聲如沸胆胰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜀涨。三九已至瞎嬉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間厚柳,已是汗流浹背佑颇。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留草娜,地道東北人挑胸。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像宰闰,于是被迫代替她去往敵國和親茬贵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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