Spring AOP ProxyFactoryBean源码笔记 一

基础定义:

  • Pointcut:切点
  • Advice:通知或增强,织入逻辑存在的地方
  • Advisor:通知器,可以将切点与通知相结合。

简单demo:

github

接口TestServiceI

public interface TestServiceI {

    void method1();

    void method2();
}

接口实现类TestServiceA

@Service
public class TestServiceA implements TestServiceI {

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

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

另一个没有实现接口的ServiceTestServiceB

@Service
public class TestServiceB {

    public void method1() {
        System.out.println("TestServiceB method1...");
    }
}

通知类MyAdvice

@Component
public class MyAdvice implements MethodBeforeAdvice, AfterReturningAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) {
        System.out.println("before...");
    }

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) {
        System.out.println("after...");
    }
}

Aop配置AopConfiguration

@Configuration
public class AopConfiguration {

    @Autowired
    private TestServiceA testServiceA;
    @Autowired
    private TestServiceB testServiceB;

    @Bean
    public ProxyFactoryBean proxyFactoryBeanA() throws ClassNotFoundException {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setProxyInterfaces(new Class[]{TestServiceI.class});
        proxyFactoryBean.setTarget(testServiceA);
        proxyFactoryBean.setInterceptorNames("myAdvice");
        return proxyFactoryBean;
    }

    @Bean
    public ProxyFactoryBean proxyFactoryBeanB() {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(testServiceB);
        proxyFactoryBean.setInterceptorNames("myAdvice");
        return proxyFactoryBean;
    }
}

运行Aop test1

public class Aop {

    @Test
    public void test1() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.tianwen.spring");
        TestServiceI testServiceA = (TestServiceI) context.getBean("proxyFactoryBeanA");
        testServiceA.method1();
        System.out.println("---");
        testServiceA.method2();
        System.out.println("---");
        TestServiceB testServiceB = (TestServiceB) context.getBean("proxyFactoryBeanB");
        testServiceB.method1();
    }
}

运行结果:

before...
TestServiceA method1...
after...
---
before...
TestServiceA method2...
after...
---
before...
TestServiceB method1...
after...

TestServiceAAopConfiguration中配置了代理接口,故代理类由JDK生成,TestServiceB的代理类由Cglib生成。

代理类的生成过程:

ProxyFactoryBeanFactoryBean 查看getObject()方法。

public class ProxyFactoryBean extends ProxyCreatorSupport
        implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
...
    public static final String GLOBAL_SUFFIX = "*";
...
    private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
...
    private transient BeanFactory beanFactory;
...
    @Override
    public Object getObject() throws BeansException {
        // 顺序1
        // 初始化通知器链
        initializeAdvisorChain();
        // 默认true
        if (isSingleton()) {
            // 顺序10
            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.");
            }
            return newPrototypeInstance();
        }
    }
...
    // 顺序1
    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
        // 是否已经初始化过
        if (this.advisorChainInitialized) {
            return;
        }
        // interceptorNames为数组。值为指定的通知或通知器在容器中的bean name。
        // interceptorNames的值,是在使用ProxyFactoryBean时配置的
        // 例如demo中的proxyFactoryBean.setInterceptorNames("myAdvice");
        if (!ObjectUtils.isEmpty(this.interceptorNames)) {
            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");
            }

            // Materialize interceptor chain from bean names.
            // 根据bean name,具体化拦截器。
            for (String name : this.interceptorNames) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Configuring advisor or advice '" + 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.
                    Object advice;
                    // 当前通知为原型还是单例
                    if (this.singleton || this.beanFactory.isSingleton(name)) {
                        // Add the real Advisor/Advice to the chain.
                        // 单例 调用容器的getBean
                        // 当前ProxyFactoryBean有实现BeanFactoryAware接口,在setBeanFactory方法中通过回调可以拿到当前IOC容器,使用变量beanFactory接收。
                        // 此用法属于spring容器的高级特性
                        // 这里可以看出,需要将这些拦截器托管给容器。否则会找不到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.
                        // 原型 new PrototypePlaceholderAdvisor
                        advice = new PrototypePlaceholderAdvisor(name);
                    }
                    // 顺序2
                    // 拿到通知后,将通知器添加到通知器链上
                    addAdvisorOnChainCreation(advice, name);
                }
            }
        }
        // 完成通知器初始化
        this.advisorChainInitialized = true;
    }
...
    // 顺序2
    private void addAdvisorOnChainCreation(Object next, String name) {
        // 顺序3
        // We need to convert to an Advisor if necessary so that our source reference
        // matches what we find from superclass interceptors.
        // 将容器中取得的bean转化为通知器
        Advisor advisor = namedBeanToAdvisor(next);
        if (logger.isTraceEnabled()) {
            logger.trace("Adding advisor with name '" + name + "'");
        }
        // 顺序7
        // 拿到通知器后,添加
        // 基类AdvisedSupport中的方法
        addAdvisor(advisor);
    }
...
    // 顺序3
    private Advisor namedBeanToAdvisor(Object next) {
        try {
            // 顺序4 顺序6
            // advisorAdapterRegistry被声明为GlobalAdvisorAdapterRegistry.getInstance();
            return this.advisorAdapterRegistry.wrap(next);
        }
        catch (UnknownAdviceTypeException ex) {
            // We expected this to be an Advisor or Advice,
            // but it wasn't. This is a configuration error.
            throw new AopConfigException("Unknown advisor type " + next.getClass() +
                    "; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +
                    "which may also be target or TargetSource", ex);
        }
    }
...
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        checkInterceptorNames();
    }
...
    // 顺序10
    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.
                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);
            // 顺序11,顺序15
            // 先创建Aop代理,再根据创建的代理生成代理对象。
            // 父类ProxyCreatorSupport中的createAopProxy()方法
            this.singletonInstance = getProxy(createAopProxy());
        }
        // 返回创建的代理对象
        return this.singletonInstance;
    }
...
    // 顺序15
    protected Object getProxy(AopProxy aopProxy) {
        // 顺序16 顺序18
        // 分别对应最下面的JdkDynamicAopProxy与CglibAopProxy的getProxy方法
        return aopProxy.getProxy(this.proxyClassLoader);
    }

GlobalAdvisorAdapterRegistry getInstance()方法

public abstract class GlobalAdvisorAdapterRegistry {
...
    // 顺序5
    // 再来看DefaultAdvisorAdapterRegistry
    private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();
...
    // 顺序4
    public static AdvisorAdapterRegistry getInstance() {
        return instance;
    }

DefaultAdvisorAdapterRegistry

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

    private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
    // 顺序5
    // 构造器 前置、后置和异常通知适配器
    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }

    // 顺序6
    @Override
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        // 如果容器中的bean已经是通知器 返回
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        // 强转为通知
        Advice advice = (Advice) adviceObject;
        // 如果通知实现MethodInterceptor接口,不需要适配器,返回默认切点通知器(DefaultPointcutAdvisor)
        if (advice instanceof MethodInterceptor) {
            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            // 否则需要判断通知是否是适配器支持的类型,实际是判断当前通知是否是前置、后置或环绕三种通知接口的实现
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        // 回到顺序3
        throw new UnknownAdviceTypeException(advice);
    }

AdvisedSupport

public class AdvisedSupport extends ProxyConfig implements Advised {
...
    private List<Class<?>> interfaces = new ArrayList<Class<?>>();
...
    private List<Advisor> advisors = new LinkedList<Advisor>();

    private Advisor[] advisorArray = new Advisor[0];
...
    private List<Advisor> advisors = new LinkedList<Advisor>();
...
    // 顺序7
    @Override
    public void addAdvisor(Advisor advisor) {
        int pos = this.advisors.size();
        // 顺序8
        addAdvisor(pos, advisor);
    }
    // 顺序8
    @Override
    public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
        // 通知器为DefaultPointcutAdvisor,false
        if (advisor instanceof IntroductionAdvisor) {
            validateIntroductionAdvisor((IntroductionAdvisor) advisor);
        }
        // 顺序9
        addAdvisorInternal(pos, advisor);
    }
...
    // 顺序9
    private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
        Assert.notNull(advisor, "Advisor must not be null");
        if (isFrozen()) {
            throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
        }
        if (pos > this.advisors.size()) {
            throw new IllegalArgumentException(
                    "Illegal position " + pos + " in advisor list with size " + this.advisors.size());
        }
        // 添加到list中,至此完成初始化通知器链,再回到ProxyFactoryBean的getObject()中。
        this.advisors.add(pos, advisor);
        // 更新到advisorArray属性中
        updateAdvisorArray();
        adviceChanged();
        // 回到顺序1
    }
...
    // 在构造ProxyFactoryBean时,调用setProxyInterfaces()方法设置代理接口时,实际调用了基类的setInterfaces方法,将代理的接口保存在当前类的interfaces属性中
    public void setInterfaces(Class<?>... interfaces) {
        Assert.notNull(interfaces, "Interfaces must not be null");
        this.interfaces.clear();
        for (Class<?> ifc : interfaces) {
            addInterface(ifc);
        }
    }

    public void addInterface(Class<?> intf) {
        Assert.notNull(intf, "Interface must not be null");
        if (!intf.isInterface()) {
            throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
        }
        if (!this.interfaces.contains(intf)) {
            this.interfaces.add(intf);
            adviceChanged();
        }
    }
...
    // 返回变量interfaces中的接口
    @Override
    public Class<?>[] getProxiedInterfaces() {
        return this.interfaces.toArray(new Class<?>[this.interfaces.size()]);
    }

ProxyCreatorSupport

public class ProxyCreatorSupport extends AdvisedSupport {
...
    public ProxyCreatorSupport() {
        // 顺序13
        this.aopProxyFactory = new DefaultAopProxyFactory();
    }
...
    // 顺序12
    public AopProxyFactory getAopProxyFactory() {
        // 顺序13
        return this.aopProxyFactory;
    }
...
    // 顺序11
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        // AopProxyFactory为DefaultAopProxyFactory,由它负责创建Aop代理
        // 顺序12 顺序14
        return getAopProxyFactory().createAopProxy(this);
    }

DefaultAopProxyFactory

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    // 顺序14
    @Override
    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.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            // 返回使用Cglib代理ObjenesisCglibAopProxy
            return new ObjenesisCglibAopProxy(config);
        }
        // 如果没有设置代理接口,返回使用Jdk代理JdkDynamicAopProxy
        else {
            return new JdkDynamicAopProxy(config);
        }
        // 回到顺序11
    }

    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        // AdvisedSupport的getProxiedInterfaces()方法
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    }

CglibAopProxy getProxy()

class CglibAopProxy implements AopProxy, Serializable {
...
@Override
    // 顺序16
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
        }

        try {
            Class<?> rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

            Class<?> proxySuperClass = rootClass;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class<?> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }

            // Validate the class, writing log messages as necessary.
            validateClassIfNecessary(proxySuperClass, classLoader);

            // Configure CGLIB Enhancer...
            // 构造CGLIB Enhancer
            Enhancer enhancer = createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader &&
                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
            // 顺序17
            // 回调方法
            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // fixedInterceptorMap only populated at this point, after getCallbacks call above
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);

            // Generate the proxy class and create a proxy instance.
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        catch (CodeGenerationException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                    this.advised.getTargetClass() + "]: " +
                    "Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (IllegalArgumentException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                    this.advised.getTargetClass() + "]: " +
                    "Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (Throwable ex) {
            // TargetSource.getTarget() failed
            throw new AopConfigException("Unexpected AOP exception", ex);
        }
    }
...
    // 顺序17
    private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        // Parameters used for optimization choices...
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isFrozen = this.advised.isFrozen();
        boolean isStatic = this.advised.getTargetSource().isStatic();

        // Choose an "aop" interceptor (used for AOP calls).
        // 使用内部类  DynamicAdvisedInterceptor作为回调
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

        // Choose a "straight to target" interceptor. (used for calls that are
        // unadvised but can return this). May be required to expose the proxy.
        Callback targetInterceptor;
        if (exposeProxy) {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
        }
        else {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
        }

        // Choose a "direct to target" dispatcher (used for
        // unadvised calls to static targets that cannot return this).
        Callback targetDispatcher = isStatic ?
                new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();

        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };

        Callback[] callbacks;

        // If the target is a static one and the advice chain is frozen,
        // then we can make some optimizations by sending the AOP calls
        // direct to the target using the fixed chain for that method.
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);

            // TODO: small memory optimization here (can skip creation for methods with no advice)
            for (int x = 0; x < methods.length; x++) {
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
                fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                        chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(methods[x].toString(), x);
            }

            // Now copy both the callbacks from mainCallbacks
            // and fixedCallbacks into the callbacks array.
            callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
            System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
            System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
            this.fixedInterceptorOffset = mainCallbacks.length;
        }
        else {
            callbacks = mainCallbacks;
        }
        return callbacks;
    }

JdkDynamicAopProxy getProxy()

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
...
    // 顺序18
    @Override
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        // JDK的Proxy类,InvocationHandler为JdkDynamicAopProxy。可以看到JdkDynamicAopProxy有实现InvocationHandler接口
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

至此,代理对象已经创建完毕。下一篇分析调用代理对象对应方法时,织入的逻辑如何工作。

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

推荐阅读更多精彩内容