spring--aop_1_源码分析之JdkDynamicAopProxy实现

aop 实现有两种方式

  1. ProxyFactoryBean方式: 这种方式是通过配置实现
  2. ProxyFactory方式:这种方式是通过编程实现

这里说 ProxyFactoryBean ,先上一张ProxyFactoryBean 的关系图,后面能用到。

示例代码:

/**

  • 代理接口,如果不是接口使用CGLIB代理
    /
    public interface ProxyInterface {
    void m();
    void t();
    }
    /
    *

  • 目标对象,接口的实现类
    */
    public class Target implements ProxyInterface {
    @Override
    public void m() {
    System.out.println("m");
    }

    @Override
    public void t() {
    System.out.println("t");
    }
    }

/**

  • 通知器
    /
    public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
    System.out.println("BeforeAdvice.....");
    }
    }
    /
    *
  • 通知器
    */
    public class AfterAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    System.out.println("AfterAdvice.....");
    }
    }
    定义一个接口ProxyInterface, 实现类为 Target,声明了两个advice,用来增强Target 方法。配置文件如下(advice 配置的顺序就是调用的顺序):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

<!-- 目标类 -->
<bean id="target" class="com.masz.springtest.aop.proxy.Target"/>

<!-- advice -->
<bean id="beforeAdvice" class="com.masz.springtest.aop.proxy.BeforeAdvice"/>
<bean id="afterAdvice" class="com.masz.springtest.aop.proxy.AfterAdvice"/>

<!-- 增强代理对象,ProxyFactoryBean 是一个FactoryBean , getBean() 时会调用它的getObject() 方法 -->
<bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

    <!-- 代理接口,如果没有接口使用CGLIB生成代理类-->
    <property name="proxyInterfaces">
        <list>
            <value>com.masz.springtest.aop.proxy.ProxyInterface</value>
        </list>
    </property>
    <property name="singleton" value="true"/>  <!-- 是否是单例 -->
    <property name="target" ref="target"/>  <!-- 指定增强目标bean -->

    <!-- 拦截器名称 -->
    <property name="interceptorNames">
        <list>
            <value>beforeAdvice</value>
            <value>afterAdvice</value>
        </list>
    </property>
</bean>

</beans>
测试:

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(AopTest.class, args);

//直接获取目标类
Target t = applicationContext.getBean(Target.class);
t.m();

//获取目标的代理。 关键的是:ProxyFactoryBean  是一个FactoryBean
ProxyInterface  proxy = (ProxyInterface)applicationContext.getBean("targetProxy");
proxy.m();
System.exit(0);

}
运行结果:

m
BeforeAdvice.....
m
AfterAdvice.....

第一个方法没有被增强,第二个方法被增强了。

源码分析:

从代码中可以看到,通过applicationContext.getBean()获取ProxyFactoryBean, ProxyFactoryBean 是一个FactoryBean 所以getObject() 方法就是获取代理对象的入口方法。

ProxyFactoryBean.getObject() 源码:

@Override
@Nullable
public Object getObject() throws BeansException {
//初始化advisor 链
initializeAdvisorChain();

//对singleton 和 prototype 类型区分,生成相应的proxy
if (isSingleton()) {
    //是singleton,调用此方法生成代理对象
    return getSingletonInstance();
}
else {
    if (this.targetName == null) {
        logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                "Enable prototype proxies by setting the 'targetName' property.");
    }
    //不是singleton,创建一个Prototype 的实例的代理对象
    return newPrototypeInstance();
}

}
initializeAdvisorChain() 初始化 advisor chain:

/**

  • 创建advisor 链。
  • advisor 信息从BeanFactory 来的,每当创建一个新的prototype实例被创建时,BeanFactory 就会被刷新。
  • 拦截器通过factory api 以编程的方式被添加,而且不受advisor改变的影响。

过程:
这个初始化advisor 链,是应用第一次通过 ProxyFactoryBean 获取代理对象时触发的,
advisor 链初始化完成之后,会读取配置中所有的通知器,这个读取比较简单就是调用容器的getBean()方法;
然后把获取的advice 加入到 advisor 链中,这个过程是addAdvisorOnChainCreation() 方法实现

*/
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
//这个是个标识位,标记通知器链是否已经初始化过了,如果已经初始化完了就直接返回。
if (this.advisorChainInitialized) {
return;
}

//配置的advice 不能是空的,如果没有配置advice就不用增强了。
if (!ObjectUtils.isEmpty(this.interceptorNames)) {

    //所有的bean 都是BeanFactory 管理的,所以BeanFactory不能是空
    if (this.beanFactory == null) {
        throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
                "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
    }

    // Globals can't be last unless we specified a targetSource using the property...
    if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
            this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
        throw new AopConfigException("Target required after globals");
    }

    //遍历所有的advice 名称配置,获取advice bean 并且添加到 advisor 链
    for (String name : this.interceptorNames) {
        if (logger.isTraceEnabled()) {
            logger.trace("Configuring advisor or advice '" + name + "'");
        }

        //interceptor name 是 * 结尾的
        if (name.endsWith(GLOBAL_SUFFIX)) {
            if (!(this.beanFactory instanceof ListableBeanFactory)) {
                throw new AopConfigException(
                        "Can only use global advisors or interceptors with a ListableBeanFactory");
            }
            addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                    name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
        }

        else {
            // If we get here, we need to add a named interceptor.
            // We must check if it's a singleton or prototype.
            //程序运行到这里就要检查添加的 interceptor 是 singleton 还是 prototype 类型。
            
            Object advice;
            if (this.singleton || this.beanFactory.isSingleton(name)) {
                // Add the real Advisor/Advice to the chain.
                //单例的 advice,就从beanFactory 中get bean 了。
                advice = this.beanFactory.getBean(name);
            }
            else {
                // It's a prototype Advice or Advisor: replace with a prototype.
                // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
                //prototype advice,要创建一个新的advice
                advice = new PrototypePlaceholderAdvisor(name);
            }
            //添加advice 到 advisor chain
            addAdvisorOnChainCreation(advice, name);
        }
    }
}
this.advisorChainInitialized = true;

}
上面方法中的 addAdvisorOnChainCreation() 方法:
把配置 advice 封装成一个 DefaultPointcutAdvisor 对象,包含了PointCut(默认是Pointcut.TRUE) 和 advice。
然后把封装成的 advisor 放到 advisors 集合中,这个过程是在 类AdvisedSupport 中实现的,ProxyFactoryBean 是这个类的子类,看上图。

getSingletonInstance() 方法, 生成 singleton 代理对象。

/**

  • Return the singleton instance of this class's proxy object,
  • lazily creating it if it hasn't been created already.
  • @return the shared singleton proxy

返回一个单例的代理对象,如果没有创建则会进行懒加载。

过程:首先读取ProxyFactoryBean 的配置,为生成代理对象做好准备,如:代理接口,目录对象等。
再通过AopProxy 生成代理对象。

*/
private synchronized Object getSingletonInstance() {
//如果已经创建了,就直接返回
if (this.singletonInstance == null) {

    this.targetSource = freshTargetSource();
    if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
        // Rely on AOP infrastructure to tell us what interfaces to proxy.
        //根据AOP 框架来判断需要代理的接口
        Class<?> targetClass = getTargetClass();
        
        if (targetClass == null) {
            throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
        }
        //设置代理对象的接口
        setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
    }
    // Initialize the shared singleton instance.
    super.setFrozen(this.freezeProxy);
    //getProxy()方法,通过createAopProxy() 方法返回的AopProxy 得到代理对象。
    this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;

}
/**

  • getProxy() 方法出现了AopProxy 接口对象。
    */
    protected Object getProxy(AopProxy aopProxy) {
    return aopProxy.getProxy(this.proxyClassLoader);
    }
    上面代码中 createAopProxy() 返回的是一个AopProxy对象,这个对象有两个实现类:JdkDynamicAopProxy,CglibAopProxy,看到名字就很清楚了分别对应生成代理类不同的实现方式。getProxy() 方法调用AopProxy 类的getProxy() 方法返回代理对象。
    Spring 使用AopProxy 接口对象把AOP代理的实现和框架其它部分区分开,体现面向接口编程。

createAopProxy() 方法是在ProxyFactoryBean 父类 ProxyCreatorSupport 中实现的,ProxyCreatorSupport 中又调用了AopProxyFactory 默认实现 DefaultAopProxyFactory.createAopProxy() 方法生成AopProxy 代理对象。

/**

  • Subclasses should call this to get a new AOP proxy. They should <b>not</b>
  • create an AOP proxy with {@code this} as an argument.

子类调用这个方法生成 AOP proxy。

在 AdvisedProxy 子类 ProxyFactoryBean 中通过 AopProxyFactory 来生成代理类,AdvisedProxy 封装了所有的生成代理对象信息,如:实现接口,目录类等。
AopProxyFactory 使用的是 DefaultAopProxyFactory,这个对象在 ProxyFactoryBean 父类 ProxyCreatorSupport 中被创建。
createAopProxy() 方法参数就是 AdvisedProxy 类型,这里传的是this,就是 ProxyFactoryBean,ProxyFactoryBean也是AdvisedProxy子类(可以查看上面的类关系图)。

*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}

//这里是调用 AopProxyFactory 默认实现 DefaultAopProxyFactory.createAopProxy() 方法生成AopProxy 代理对象。
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {

    //目录对象的class
    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.");
    }
    //targetClass 是接口类,使用 JDK来生成 Proxy
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
        return new JdkDynamicAopProxy(config);
    }
    //如果不是接口类,使用CGLIB 生成代理对象
    return new ObjenesisCglibAopProxy(config);
}
else {
    return new JdkDynamicAopProxy(config);
}

}
JdkDynamicAopProxy 源码分析:

JdkDynamicAopProxy 本身实现了 InvocationHandler 接口和 AopProxy 接口所以 JdkDynamicAopProxy实现的InvocationHandler.invoker() 方法就是Proxy 对象回调的方法。
实现的AopProxy.getProxy() 方法就是通过JDK动态代理生成的代理对象,传递的InvocationHandler 对象就是 JdkDynamicAopProxy 自身。
这就是动态代理了,切面的实惠就是在 invoke() 方法中体现的。后面再分析如何实现AOP。

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
//获取目标类上的接口并且判断是否需要添加SpringProxy Advised DecoratingProxy(spring4.3 新增) 接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);

//判断的目标对象实现的接口是否定义了equals或hashCode方法,
//在invoke() 方法调用的时候会对 equals 和 equals 做特殊的处理,参考后面
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

//返回动态代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

}
总结:
通过AopProxy 对象封装target 目标对象之后,ProxyFactoryBean方法得到的对象已经是一个AopProxy代理对象了,在ProxyFactoryBean 中配置的target目标对象不会让应用直接调用其方法的实现,对target目标对象的方法调用会被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。对于 JDK的AopProxy代理对象,使用的是InvocationHander的invoker 回调入口。对于CGLIB的AopProxy代理对象,使用的是设置好的callbak 回调,在这里callback回调中,对于AOP的实现是通过DynamicAdvisedInterceptor 来完成的,DynamicAdvisedInterceptor 的回调入口是 intercept 方法(后面再分析CGLIB)。
这里只是AopProxy 代理对象的生成,通过这个过程把代理对象和拦截器待调用的部分都准备好。下面就分析AOP运行过程中对这些拦截器和代理对象的调用过程。

AOP 拦截器调用实现:

如果是JDK实现的代理对象就会通过InvocationHandler 来完成拦截器回调,如果是CGLIB 就通过DynamicAdvisedInterceptor 来完成回调。
JdkDynamicAopProxy 的 invoke 拦截:
在 JdkDynamicAopProxy.getProxy() 方法中,调用的的JDK动态代理生成代理类,JdkDynamicAopProxy 自身实现了InvocationHandler 接口,那么代理对象调用目标对象方法时会被invoke() 方法拦截

JdkDynamicAopProxy.invoke() 源码:

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

//从advised中获取目标对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;

try {
    if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
        // The target does not implement the equals(Object) method itself.
        //目标对象没有重写Object 的equals() 方法
        return equals(args[0]);
    }
    else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
        // The target does not implement the hashCode() method itself.
        //目标对象没有重写 Object的 hashCode() 方法
        return hashCode();
    }
    else if (method.getDeclaringClass() == DecoratingProxy.class) {
        // There is only getDecoratedClass() declared -> dispatch to proxy config.
        // 如果方法是在DecoratingProxy声明的,
        // DecoratingProxy 只有getDecoratedClass() 一个方法,所有在这里直接调用
        // 返回代理类的终极目标类。
        return AopProxyUtils.ultimateTargetClass(this.advised);
    }
    else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
        // Service invocations on ProxyConfig with the proxy config...
        //Spring AOP不会增强直接实现Advised接口的目标对象。
        //这里直接通过反射调用。
        return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    }

    //返回值
    Object retVal;

    //是否暴露代理对象,如果暴露意味着在线程内共享代理对象,在线程内可通过AopContext 获取代理对象。就是通过ThreadLocal 实现的。
    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.
    // 目标对象
    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.
    // 检查是否的拦截器,如果没有那么就直接通过反射调用目标方法,MethodInvocation就不用创建了
    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.
        //如果没有拦截器,就不用创建 MethodInvocation,直接在目标对象上反射调用方法
        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    }
    else {
        // We need to create a method invocation...
        //创建一个 ReflectiveMethodInvocation,这个类是实现AOP的功能的封装
        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();
    // retVal不空 并且和目标方法的返回类型一致,就返回。
    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);
    }
}

}
注:
invoke 方法中获取调用拦截器链方法
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
这个方法把 PintcutAdvice 封装成 MethodInterceptor。MethodInterceptor 有两个实现类具体的为 MethodBeforeAdviceInterceptor 和 AfterReturningAdviceInterceptor
MethodInterceptor.invoke() 方法,将的 ReflectiveMethodInvocation.proceed() 中被调用,MethodInterceptor.invoke()方法的参数就是 MethodInvocation 类型,而 ReflectiveMethodInvocation 是 MethodInvocation 的子类,在invoke() 方法中又回调了 MethodInvocation.proceed()方法,这样就又回调回去了,当 "this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1" 时也就是拦截器调用完了,就通过反射调用目标方法。
ReflectiveMethodInvocation 和 MethodInterceptor 就是实现Spring AOP 的核心所在。具体查看MethodBeforeAdviceInterceptor 和 AfterReturningAdviceInterceptor 这个两个实现源码就

JdkDynamicAopProxy AOP功能,就是通过 ReflectiveMethodInvocation 类实现的

ReflectiveMethodInvocation.proceed() 源码分析:

//这个方法是递归方法,当所有拦截器都执行完毕了,就通过反射调用目标方法返回。
@Override
@Nullable
public Object proceed() throws Throwable {

//  We start with an index of -1 and increment early.
//使用 currentInterceptorIndex 记录拦截器调用的下标,当所有拦截器都调用完毕后,通过反射调用目标方法。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    //反射调用目标方法
    return invokeJoinpoint();
}

//从拦截器链中获取一个拦截器,下标是  ++this.currentInterceptorIndex
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;
            
    //如果方法和定义的切点匹配成功就执行
    if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
        return dm.interceptor.invoke(this);
    }
    else {
        // Dynamic matching failed.
        // Skip this interceptor and invoke the next in the chain.
        return proceed();
    }
}
else {
    // It's an interceptor, so we just invoke it: The pointcut will have
    // been evaluated statically before this object was constructed.
    //执行到这里就是一个 MethodInterceptor , 则直接调用
    return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

}
在示例代码中配置的是通知器,不是切面,如果配置的是切面就要走动态匹配了(动态匹配就是走jdk的正则匹配 MethodMatcher ,不扩展了)。

总结:每个 MethodInterceptor 对应的都有实现AfterReturningAdviceInterceptor, MethodBeforeAdviceInterceptor, ThrowsAdviceInterceptor。如 MethodBeforeAdviceInterceptor

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

则是调用完invoke() 方法后,就又调用了MethodInvocation.proceed() 方法,又回到了上一步方法中,这样一直循环调用,直到所有的interceptor 调用完毕。

总结:ProxyFactoryBean 通过jdk动态代理机制生成代理对象,当调用代理对象方法时,会被invoke() 方法拦截。在invoke() 方法中又获取了此方法的拦截器,通过对拦截器的调用实现了spring aop功能。CGLIB的实现只是生成代理对象的方式不同,这就让拦截器的入口有了变化。拦截器的生成和调用机制是一样的。看第二篇。

注:这里通过 initializeAdvisorChain(); 把advice 封装成了advisor,又如何把advisor 封装成具体的interceptor 呢? 看后续...
————————————————
版权声明:本文为CSDN博主「Jamin_Ma」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/convict_eva/article/details/81084833

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

推荐阅读更多精彩内容