Spring AOP原理 (三)创建AOP代理

我们在 Spring AOP原理 (二)AnnotationAwareAspectJAutoProxyCreator的执行时机,中已经了解到AnnotationAwareAspectJAutoProxyCreator 是如何创建的,她和BeanPostProcessor又有什么异同。AnnotationAwareAspectJAutoProxyCreator继承了抽象类AbstractAutoProxyCreator,
我们在此打一个断点,直到beanClass是我们自己加入容器中的com.funtl.hello.spring.cloud.eureka.aop.MathCalculator

图1

下面是postProcessBeforeInstantiation方法的代码,我们一步一步的看都做了什么

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        Object cacheKey = this.getCacheKey(beanClass, beanName);
        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            } 
//这里设置不需要增强的bean 状态设置为false
            if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) { 
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }

            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            return null;
        }
    }

1 每一个bean 创建之前,调用postProcessBeforeInstantiation();关心MathCalculator和LogAspect 的创建

1.1 判断当前bean是否在adviseBeans中(保存了所有需要增强的bean)

图2

1.2 当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,是否是切面AbstractAutoProxyCreator 代码如下

protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = 
Advice.class.isAssignableFrom(beanClass) || 
Pointcut.class.isAssignableFrom(beanClass) ||
 Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass);
        if (retVal && this.logger.isTraceEnabled()) {
            this.logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
        }

        return retVal;
    }

AnnotationAwareAspectJAutoProxyCreatorAbstractAutoProxyCreator 子类 isInfrastructureClass方法覆盖了父类的isInfrastructureClass()方法同时调用super.isInfrastructureClass(beanClass),代码如下

  protected boolean isInfrastructureClass(Class<?> beanClass) {
        return super.isInfrastructureClass(beanClass) || this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass);
    }

this.aspectJAdvisorFactory.isAspect(beanClass)判断是否是一个切面

  public boolean isAspect(Class<?> clazz) {
        return this.hasAspectAnnotation(clazz) && !this.compiledByAjc(clazz);
    }

1.3 是否需要跳过

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
        //找到候选的增强器(切面通知方法)
        List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
        Iterator var4 = candidateAdvisors.iterator();

        Advisor advisor;
        do {
            //如果不满足增强器的类型调用父类的shouldSkip。
            if (!var4.hasNext()) {
                return super.shouldSkip(beanClass, beanName);
            }

            advisor = (Advisor)var4.next();
        } while(!(advisor instanceof AspectJPointcutAdvisor) || !((AspectJPointcutAdvisor)advisor).getAspectName().equals(beanName));

        return true;
    }

找到候选的增强器(切面通知方法),每一个封装的通知方法的增强器是InstantiationModelAwarePointcutAdvisor类型的

image.png

image.png

image.png

不满足advisor instanceof AspectJPointcutAdvisor) || !((AspectJPointcutAdvisor)advisor).getAspectName().equals(beanName)的判断所以调用父类的super.shouldSkip(beanClass, beanName),父类直接返回false

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
        return false;
    }

2. 创建对象

 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
        if (bean != null) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }

        return bean;
    }
  protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
//这里判断这个bean是否是之前已经将增强状态设置为false ,如果是直接返回不需要使用动态代理生成新对象(第一段代码第9行)
        } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
//获取当前bean 的所有增强器`Object[] specificInterceptors`(通知方法)
            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
            if (specificInterceptors != DO_NOT_PROXY) {
//将当前bean 以增强的bean的放入到 advisedBeans 中
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            } else {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    }

2.1 获取当前bean 的所有增强器(通知方法)
2.1.1 找到候选的所有增强器(找到哪些通知方法是需要切入当前bean 的)

   @Nullable
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
        //候选MathCalculator 的增强器(切面)
        List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
        return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
    }
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        //候选增强器
        List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
        //找出可以使用的增强器
        List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        this.extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
        }

        return eligibleAdvisors;
    }
 protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
        ProxyCreationContext.setCurrentProxiedBeanName(beanName);

        List var4;
        try {
            //使用aop工具找到增强器
            var4 = AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
        } finally {
            ProxyCreationContext.setCurrentProxiedBeanName((String)null);
        }

        return var4;
    }
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        } else {
            List<Advisor> eligibleAdvisors = new LinkedList();
            Iterator var3 = candidateAdvisors.iterator();

            while(var3.hasNext()) {
                Advisor candidate = (Advisor)var3.next();
                if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                    eligibleAdvisors.add(candidate);
                }
            }

            boolean hasIntroductions = !eligibleAdvisors.isEmpty();
            Iterator var7 = candidateAdvisors.iterator();

            while(var7.hasNext()) {
                Advisor candidate = (Advisor)var7.next();
                if (!(candidate instanceof IntroductionAdvisor) && canApply(candidate, clazz, hasIntroductions)) {
                //获得能用的增强器,能够用的增强器都加入 eligibleAdvisors 返回
                    eligibleAdvisors.add(candidate);
                }
            }

            return eligibleAdvisors;
        }
    }

下面就开始算切入点表达式和 MathCalculator是否能够匹配

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
        if (advisor instanceof IntroductionAdvisor) {
            return ((IntroductionAdvisor)advisor).getClassFilter().matches(targetClass);
        } else if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pca = (PointcutAdvisor)advisor;
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        } else {
            return true;
        }
    }

2.1.2 获取能在bean 使用的增强器
2.1.3 给增强器排序
2.2 保存当前bean(已增强)在adviseBeans(存放增强的bean)中
2.3 如果当前bean 需要增强器,创建当前bean 的代理对象this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

 protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
        }
//创建ProxyFactory  工厂
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);
        if (!proxyFactory.isProxyTargetClass()) {
            if (this.shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            } else {
                this.evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }
        //拿到增强器 
        Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
      //增强器放到代理工厂
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        this.customizeProxyFactory(proxyFactory);
        proxyFactory.setFrozen(this.freezeProxy);
        if (this.advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
      //用代理工厂帮我们创建对象
        return proxyFactory.getProxy(this.getProxyClassLoader());
    }

2.3.1 获取所有增强器(通知方法)
2.3.2 保存到proxyfactory中
2.3.3 创建代理对象Spring 自动决定(有实现接口的使用jdk没有的使用cglib) new JdkDynamicAopProxy(config) new ObjenesisCglibAopProxy(config) 两种
2.4 给容器返回当前组件使用cglib增强了的代理对象
2.5 以后容器中获取到的就是这个组件的代理对象,执行目标方法时,代理对象就会执行通知方法的流程

3. 目标方法执行:

容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象等)


image.png
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Object target = null;
            TargetSource targetSource = this.advised.getTargetSource();

            Object var16;
            try {
                if (this.advised.exposeProxy) {
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }

                target = targetSource.getTarget();
                Class<?> targetClass = target != null ? target.getClass() : null;
              //获取将要执行的目标方法的拦截器链
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                  //如果拦截器链为空的,直接执行目标方法
                    retVal = methodProxy.invoke(target, argsToUse);
                } else {
                  //如果有拦截器链
                    retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
                }

                retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
                var16 = retVal;
            } finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }

                if (setProxyContext) {
                    AopContext.setCurrentProxy(oldProxy);
                }

            }

            return var16;
        }
 public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
        AdvisedSupport.MethodCacheKey cacheKey = new AdvisedSupport.MethodCacheKey(method);
        List<Object> cached = (List)this.methodCache.get(cacheKey);
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }

        return cached;
    }

遍历所有增强器,并将增强器封装为Interceptor

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
        List<Object> interceptorList = new ArrayList(config.getAdvisors().length);
        Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass();
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        Advisor[] var8 = config.getAdvisors();
        int var9 = var8.length;

        for(int var10 = 0; var10 < var9; ++var10) {
            Advisor advisor = var8[var10];
            MethodInterceptor[] interceptors;

            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        if (mm.isRuntime()) {
                            MethodInterceptor[] var15 = interceptors;
                            int var16 = interceptors.length;

                            for(int var17 = 0; var17 < var16; ++var17) {
                                MethodInterceptor interceptor = var15[var17];
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        } else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            } else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor)advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            } else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }

        return interceptorList;
    }

3.1 CglibAopProxy.intercept();拦截目标方法执行
3.2 获取将要执行的目标方法的拦截器链

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

3.2.1 List<Object> interceptorList = new ArrayList(config.getAdvisors().length); config.getAdvisors() 含有五个增强器一个默认的ExposeInvocationInterceptor和四个我们定义的增强器(切入方法)
3.2.2 遍历所有增强器,将其转为 interceptors = registry.getInterceptors(advisor);

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

        Iterator var4 = this.adapters.iterator();

        while(var4.hasNext()) {
            AdvisorAdapter adapter = (AdvisorAdapter)var4.next();
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }

        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        } else {
            return (MethodInterceptor[])interceptors.toArray(new MethodInterceptor[0]);
        }
    }

3.2.3 将增强器转为List<MethodInterceptor>

image.png

3.3 如果没有拦截器链直接执行目标方法
拦截器链(每一个通知方法又被包装为拦截器,利用MethodInterceptor机制)

retVal = methodProxy.invoke(target, argsToUse);

3.4 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入,并创建一个CglibMethodInvocation对象,并调用proceed();

 retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();

3.5 拦截器链的触发过程

@Nullable
    public Object proceed() throws Throwable {
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//没有拦截器链调用反射执行目标方法具体代码可以自己点进去看看 最终执行的是method.invoke(target, args);
            return this.invokeJoinpoint();
        } else {
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
            } else {
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }

3.5 拦截器链的触发过程
3.5.1 如果没有拦截器执行目标方法,或者拦截器的索引和拦截器数组-1大小一样执行目标方法
3.5.2 链式获取每一个拦截器,拦截器执行invoke 方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;拦截器链的机制保证通知方法与目标方法的执行顺序


开始看这个拦截器链的调用过程

image.png

这里有五个拦截器
private int currentInterceptorIndex = -1;默认从-1开始
++this.currentInterceptorIndex索引+1
image.png

执行索引为0 的拦截器ExposeInvocationInterceptorinvoke()方法
进入invoke()方法

public Object invoke(MethodInvocation mi) throws Throwable {
        MethodInvocation oldInvocation = (MethodInvocation)invocation.get();
        invocation.set(mi);

        Object var3;
        try {
            var3 = mi.proceed();
        } finally {
            invocation.set(oldInvocation);
        }

        return var3;
    }

这里执行var3 = mi.proceed(); mi就是((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);的this 所以等于又递归调用proceed()方法
此时currentInterceptorIndex=1调用第二个拦截器AspectJAfterThrowingAdvice (异常通知)的invoke()方法

   public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        } catch (Throwable var3) {
            if (this.shouldInvokeOnThrowing(var3)) {
                this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, var3);
            }

            throw var3;
        }
    }

return mi.proceed();同上继续返回调用currentInterceptorIndex=2,调用第三个拦截器AfterReturningAdviceInterceptor (返回通知)的invoke()方法

  public Object invoke(MethodInvocation mi) throws Throwable {
        Object retVal = mi.proceed();
      //返回通知可以获得返回值
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }

return mi.proceed();同上继续返回调用currentInterceptorIndex=3, 调用第四个拦截器AspectJAfterAdvice (后置通知)的invoke()方法

  public Object invoke(MethodInvocation mi) throws Throwable {
        Object var2;
        try {
            var2 = mi.proceed();
      //后置通知就是无论成功与否都会在finally中调用
        } finally {
            this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);
        }

        return var2;
    }

return mi.proceed();同上继续返回调用currentInterceptorIndex=4, 调用第五个拦截器MethodBeforeAdviceInterceptor (前置通知)的invoke()方法

    public Object invoke(MethodInvocation mi) throws Throwable {
//在调用前 执行通知方法
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }

此时控制台打印结果为

div方法运行参数列表是:{}

前置通知率先执行。代码继续往下走 currentInterceptorIndex=4 this.interceptorsAndDynamicMethodMatchers.size() - 1=4

image.png

执行目标方法控制台输出:

div方法运行参数列表是:{}
MathCalculator=====6  div  2  a/b=3

递归返回到上一个调用返回的地方


image.png

F7,代码继续往下走,此时控制台输出

div方法运行参数列表是:{}
MathCalculator=====6  div  2  a/b=3
div运行结束

此时递归调用到


image.png

F7,代码继续往下走,此时控制台输出

div方法运行参数列表是:{}
MathCalculator=====6  div  2  a/b=3
div运行结束
除法正常返回,运行结果是:{3.0}

此时递归返回到


image.png

F7,代码继续往下走,因为无异常所以无输出,断点到


image.png

如果出现异常
div方法运行参数列表是:{}
div运行结束
div异常信息是:{java.lang.ArithmeticException: / by zero}

拦截牵连调用关系图


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

推荐阅读更多精彩内容