[Spring]Spring AOP創(chuàng)建動(dòng)態(tài)代理的過(guò)程

Spring AOP的大致流程

我們?cè)谥暗?章中,知曉了Spring AOPBeanPostProcessor的幾個(gè)關(guān)鍵接口做了介入,分為幾個(gè)關(guān)鍵點(diǎn):

  1. 將切面類進(jìn)行解析成advisors,其中包括解析XML和被@Aspect注解標(biāo)注的Java切面類.
  2. 在初始化Bean的階段,將advisors對(duì)當(dāng)前Bean進(jìn)行篩選垮斯,獲取到當(dāng)前Bean匹配的advisors.
  3. 進(jìn)行動(dòng)態(tài)代理類的創(chuàng)建.

今天早处,我們就來(lái)看看動(dòng)態(tài)代理類在Spring AOP中是怎樣去創(chuàng)建出來(lái)的.

創(chuàng)建動(dòng)態(tài)代理的入口:wrapIfNecessary

  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // beanName不為空,并且存在于targetSourcedBeans中,也就是自定義的TargetSource被解析過(guò)了
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 如果Bean為advisedBeans撞蚕,也不需要被代理
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // isInfrastructureClass和shouldSkip的作用:
    // 識(shí)別切面類验庙,加載切面類成advisors
    // 為什么又執(zhí)行一次是因?yàn)榇嬖谘h(huán)依賴的情況下無(wú)法加載advisor
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 返回匹配當(dāng)前Bean的所有Advice顶吮、Advisor、Interceptor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 創(chuàng)建Bean對(duì)應(yīng)的代理粪薛,SingletonTargetSource用于封裝實(shí)現(xiàn)類的信息
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    // 下次代理的時(shí)候直接從緩存拿出判斷悴了,不需要重復(fù)代理
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}
  1. targetSourcedBeans存儲(chǔ)了用戶自定義的targetSource,這部分的bean在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation中已經(jīng)進(jìn)行了createProxy的處理违寿,所以在自動(dòng)化代理的環(huán)節(jié)中湃交,要過(guò)濾掉這部分的bean.
  2. advisedBeans存儲(chǔ)了已經(jīng)被Spring AOP處理過(guò)的bean,這部分的bean也是需要進(jìn)行過(guò)濾的.
  3. 進(jìn)行isInfrastructureClassshouldSkip的處理藤巢,這兩個(gè)方法在之前的文章已經(jīng)做了詳細(xì)的解析搞莺,它們的主要作用是:識(shí)別切面類、解析切面類掂咒。之所以再重復(fù)調(diào)用一次才沧,是為了收尾的工作.
  4. getAdvicesAndAdvisorsForBean獲取當(dāng)前bean匹配的advisors.
  5. 將當(dāng)前bean緩存到advisedBeans,創(chuàng)建動(dòng)態(tài)代理-createProxy,緩存proxyType. 這里無(wú)論是否能獲取到bean的advisors迈喉,都會(huì)做緩存到advisedBeans的步驟.已確保不重復(fù)處理同一個(gè)bean.

創(chuàng)建動(dòng)態(tài)代理:createProxy

  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // 如果beanFactory是ConfigurableListableBeanFactory的類型,暴露目標(biāo)類
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    // 創(chuàng)建一個(gè)ProxyFactory,當(dāng)前ProxyCreator在創(chuàng)建代理時(shí),將需要用到的字段賦值到ProxyFactory中去
    ProxyFactory proxyFactory = new ProxyFactory();
    // 將當(dāng)前的AnnotationAwareAspectJAutoProxyCreator對(duì)象的屬性賦值給ProxyFactory對(duì)象
    // 加載一些ProxyConfig
    proxyFactory.copyFrom(this);
    // 處理proxyTargetClass屬性
    // 如果希望使用CGLIB進(jìn)行代理温圆,配置proxyTargetClass為true
    if (!proxyFactory.isProxyTargetClass()) {
        // 檢查相應(yīng)BeanDefinition的“ preserveTargetClass”屬性
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            // 1. 有接口的挨摸,調(diào)用一次或者多次:proxyFactory.addInterface(ifc);
            // 2. 沒(méi)有接口的,調(diào)用: proxyFactory.setProxyTargetClass(true);
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    // 這個(gè)方法主要是對(duì)前面?zhèn)鬟f進(jìn)來(lái)的橫切邏輯實(shí)例進(jìn)行包裝
    // specificInterceptors中有Advice和Interceptor,它們都會(huì)被包裝成Advisor
    // 調(diào)用的先后順序岁歉,通過(guò)方法中的applyCommonInterceptorsFirst參數(shù)進(jìn)行設(shè)置
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    // 擴(kuò)展實(shí)現(xiàn)得运,子類可以定制proxyFactory
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    // 設(shè)置preFiltered的屬性值,默認(rèn)為false.子類:AbstractAdvisorAutoProxyCreator修改為true
    // preFiltered字段的意思是:是否為特定目標(biāo)類篩選Advisor
    // 該字段和DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice獲取所有的Advisors
    // CglibAopProxy和JdkDynamicAopProxy都會(huì)調(diào)用此方法,然后遞歸執(zhí)行所有的advisor
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(getProxyClassLoader());
}
  1. 如果當(dāng)前的beanFactory屬于ConfigurableListableBeanFactory類型,給當(dāng)前bean對(duì)應(yīng)的BeanDefinition設(shè)置上屬性"originalTargetClass"為targetClass.
  2. 先new一個(gè)ProxyFactory實(shí)例锅移,并根據(jù)AnnotationAwareAspectJAutoProxyCreator的配置進(jìn)行proxyTargetClass澈圈、optimizeexposeProxy帆啃、frozen瞬女、opaque的屬性設(shè)置.
  3. Spring不僅提供了對(duì)所有bean生效的proxyTargetClass設(shè)置,也提供了對(duì)單個(gè)bean的動(dòng)態(tài)代理配置preserveTargetClass.
  4. 調(diào)用buildAdvisors對(duì)specificInterceptors進(jìn)行適配努潘,封裝成advisor.有興趣的可以看看org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#wrap.
  5. 配置advisors诽偷、targetSourcefrozen等屬性后,進(jìn)行動(dòng)態(tài)代理的創(chuàng)建.
  6. proxyFactory.getProxy(getProxyClassLoader()),進(jìn)行動(dòng)態(tài)代理生成.

getProxy: 根據(jù)當(dāng)前bean選擇JDK或者CGLIB動(dòng)態(tài)代理

  • org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
    // 首先獲取AopProxy對(duì)象疯坤,其主要有兩個(gè)實(shí)現(xiàn):JdkDynamicAopProxy和ObjenesisCglibAopProxy
    // 分別用于JDK和CGLIB代理類的生成报慕,其getProxy方法則用于獲取具體的代理對(duì)象
    return createAopProxy().getProxy(classLoader);
}

ProxyFactoryProxyCreatorSupport的子類,在ProxyCreatorSupport中有一個(gè)createAopProxy方法压怠,從這里可以獲取到具體的代理工廠類.

  • org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
    // 激活A(yù)dvisedSupportListener監(jiān)聽(tīng)器
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}
  1. activate方法主要是用來(lái)激活A(yù)dvisedSupportListener的.
  2. 重點(diǎn)方法是這個(gè):getAopProxyFactory().createAopProxy(this);其中,getAopProxyFactory中存儲(chǔ)了一個(gè)DefaultAopProxyFactory,它實(shí)現(xiàn)了AopProxyFactory接口,接口方法createAopProxy才是真正獲取代理工廠的地方.
  • org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    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.");
        }
        // 如果要代理的類本身就是接口
        // 或者它已經(jīng)是JDK的代理類(Proxy子類)
        // 使用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);
    }
}

這里就會(huì)看到我們很熟悉的一個(gè)邏輯:實(shí)現(xiàn)了接口的bean,Spring會(huì)使用JDK動(dòng)態(tài)代理;否則使用CGLIB代理.

工廠模式:JdkDynamicAopProxy和ObjenesisCglibAopProxy

代理策略選擇

由于篇幅的原因眠冈,我選擇講解JdkDynamicAopProxy這種模式生成代理的源碼解析.

  • org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
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);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // JdkDynamicAopProxy本身實(shí)現(xiàn)了InvocationHandler接口
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

關(guān)于JDK如何生成動(dòng)態(tài)代理的原理,這里不做過(guò)多的分析了菌瘫,這在我之前的博客中有關(guān)于JDK和CGLIB生成Proxy的文章蜗顽,不了解的讀者可以去看看:
點(diǎn)我前往
在生成代理之后,Proxy就會(huì)調(diào)用InvocationHandler.invoke方法雨让,所以關(guān)于Spring AOP的代理攔截鏈執(zhí)行流程雇盖,我們直接去到invoke解析即可。

  • org.springframework.aop.framework.JdkDynamicAopProxy#invoke
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler

首先,JdkDynamicAopProxy實(shí)現(xiàn)了InvocationHandler接口,動(dòng)態(tài)代理類最終會(huì)執(zhí)行InvocationHandler.invoke.

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

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

    try {
        // equals方法不需要代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashcode方法不需要代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 如果當(dāng)前方法是Spring織入的DecoratingProxy接口中的方法栖忠,返回目標(biāo)對(duì)象的class類型
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 如果被代理的對(duì)象本身實(shí)現(xiàn)了Advised接口崔挖,則證明該類里面的方法已經(jīng)被代理了,直接執(zhí)行即可
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // Service invocations on ProxyConfig with the proxy config...
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;
        // 是否暴露代理引用
        if (this.advised.exposeProxy) {
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // Get as late as possible to minimize the time we "own" the target,
        // in case it comes from a pool.
        // 獲取目標(biāo)類
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // Get the interception chain for this method.
        // 獲取方法的攔截鏈
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // Check whether we have any advice. If we don't, we can fallback on direct
        // reflective invocation of the target, and avoid creating a MethodInvocation.
        // 如果該方法上沒(méi)有匹配的攔截器庵寞,直接反射調(diào)用Method.invoke(target,args)
        if (chain.isEmpty()) {
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            // We need to create a method invocation...
            // 創(chuàng)建ReflectiveMethodInvocation
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            retVal = invocation.proceed();
        }

        // Massage return value if necessary.
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            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 (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
  1. Spring AOP不對(duì)equals和hashCode做代理.
  2. 如果當(dāng)前方法是Spring織入的DecoratingProxy接口中的方法狸相,返回目標(biāo)對(duì)象的class類型.
  3. 如果被代理的對(duì)象本身實(shí)現(xiàn)了Advised接口,則證明該類里面的方法已經(jīng)被代理了捐川,直接執(zhí)行即可
  4. 查看當(dāng)前配置判斷是否暴露代理引用脓鹃,可以來(lái)解決this調(diào)用引起的代理失效等問(wèn)題.
  5. 從targetSource中獲取target信息.獲取當(dāng)前method的攔截鏈路.getInterceptorsAndDynamicInterceptionAdvice會(huì)對(duì)method的攔截鏈進(jìn)行緩存,如果沒(méi)有緩存属拾,會(huì)執(zhí)行org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice重新對(duì)method進(jìn)行match.
  6. getInterceptorsAndDynamicInterceptionAdvice獲取到chain之后,如果chain為空将谊,那么直接激活method.
  7. 如果chain不為空,生成ReflectiveMethodInvocation,從JavaDoc可以知道,這是一個(gè)Spring實(shí)現(xiàn)了AOP Alliance MethodInvocation接口的類渐白,關(guān)鍵方法:invokeJoinpoint(激活連接點(diǎn)方法)尊浓、proceed(執(zhí)行攔截鏈邏輯).
  8. 執(zhí)行proceed.
  9. 處理返回值。包裝此返回值(如果有必要作為代理)纯衍,并驗(yàn)證沒(méi)有將null作為原語(yǔ)返回栋齿。這是什么意思呢:假設(shè)方法返回的是int,增強(qiáng)around方法返回了null,這就會(huì)報(bào)錯(cuò),因?yàn)榛A(chǔ)數(shù)據(jù)類型都有默認(rèn)值.
  10. 釋放資源、重新設(shè)置一次代理引用.

這里最關(guān)鍵的的看chain的執(zhí)行過(guò)程襟诸,整個(gè)Spring AOP攔截鏈執(zhí)行的過(guò)程采用了一種遞歸的方式瓦堵,值得一品.

代理類執(zhí)行鏈路

  • org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
    // We start with an index of -1 and increment early.
    // 如果攔截器執(zhí)行完了,則執(zhí)行連接點(diǎn)
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }
    // 從0開(kāi)始執(zhí)行,每次遞歸進(jìn)來(lái)都會(huì)+1
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        // 動(dòng)態(tài)匹配:運(yùn)行時(shí)參數(shù)是否滿足匹配條件
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // Dynamic matching failed.
            // Skip this interceptor and invoke the next in the chain.
            // 動(dòng)態(tài)匹配失敗歌亲,進(jìn)入下一個(gè)攔截器
            return proceed();
        }
    }
    else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        // 執(zhí)行當(dāng)前攔截器
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}
  1. 在遇到AfterThrowing菇用、AfterRetruningAfter這類advice的時(shí)候陷揪,它們會(huì)執(zhí)行mi.proceed回到chain中.
  2. 回到chain中后惋鸥,列表索引自增,往下執(zhí)行下一個(gè)advice.
  3. 依次遞歸悍缠,直到遇到Around通知卦绣,執(zhí)行around.
  4. 在around中執(zhí)行joinPoint.proceed又會(huì)回到chain中.
  5. 遞歸到Before,執(zhí)行before,然后回到around的后置代碼塊中.
  6. 回溯到afterafterReturning,如果有異常飞蚓,執(zhí)行afterThrowing.
執(zhí)行流程圖
proceed

總結(jié)

  • 1. 生成代理類通過(guò)工廠模式進(jìn)行生成,實(shí)現(xiàn)接口默認(rèn)使用JDK動(dòng)態(tài)代理滤港,否則使用CGLIB
  • 2. Spring AOP通過(guò)后置處理器的postProcessAfterInitialization方法調(diào)用wrapIfNessary對(duì)Bean進(jìn)行代理并替換.
  • 3. 代理類執(zhí)行攔截鏈通過(guò)chain進(jìn)行遞歸proceed來(lái)執(zhí)行每個(gè)通知的方法
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市趴拧,隨后出現(xiàn)的幾起案子溅漾,更是在濱河造成了極大的恐慌,老刑警劉巖著榴,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件樟凄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡兄渺,警方通過(guò)查閱死者的電腦和手機(jī)缝龄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)挂谍,“玉大人叔壤,你說(shuō)我怎么就攤上這事】谛穑” “怎么了炼绘?”我有些...
    開(kāi)封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)妄田。 經(jīng)常有香客問(wèn)我俺亮,道長(zhǎng)驮捍,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任脚曾,我火速辦了婚禮东且,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘本讥。我一直安慰自己珊泳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布拷沸。 她就那樣靜靜地躺著色查,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撞芍。 梳的紋絲不亂的頭發(fā)上秧了,一...
    開(kāi)封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音序无,去河邊找鬼示惊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛愉镰,可吹牛的內(nèi)容都是我干的米罚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼丈探,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼录择!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碗降,我...
    開(kāi)封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤隘竭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后讼渊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體动看,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年爪幻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了菱皆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挨稿,死狀恐怖仇轻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情奶甘,我是刑警寧澤篷店,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站臭家,受9級(jí)特大地震影響疲陕,放射性物質(zhì)發(fā)生泄漏方淤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一蹄殃、第九天 我趴在偏房一處隱蔽的房頂上張望携茂。 院中可真熱鬧,春花似錦窃爷、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至钱慢,卻和暖如春逮京,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背束莫。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工懒棉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人览绿。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓策严,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親饿敲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子妻导,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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