Spring IoC - 依赖注入 源码解析

undefined

前言

上一篇文章中,我们介绍了Spring IoC 的容器初始化过程 - IoC 容器初始化

本篇文章中,我们继续介绍Spring IoC 依赖注入的过程和源码解读。

还是如之前一样,为大家梳理一下步骤流程,以便于大家能在心里有个大概的脉络,更容易读懂源码,更容易抓住重点。

主要内容:

  • beanName 解析转换
  • 手动注册Bean检测
  • 双亲容器检测
  • 依赖初始化(递归)
  • ★ 创建singleton 实例
  • 对象实例化
  • 属性装配
  • 处理Bean创建之后的各种回调事件
  • ...

源码解析

上一章最后一节,容器初始化的倒数第二步,finishBeanFactoryInitialization(beanFactory)实例化所有单例,调用了getBean()方法来做singleton bean 的实例化操作。这就是Spring IoC 依赖注入的入口。

在开始之前,有一点需要提一下。前面我们是从容器初始化之后进来的,但实际操作中,我们有可能是在程序普通运行情况下,用ApplicationContext.getBean()去获取容器中bean。不要局限于刚刚的视角中。

现在让我们开始吧。

首先看看getBean()

源码位置:AbstractBeanFactory#getBean(String name)

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

doGetBean()

deGetBean()

  • beanName 解析转换
  • 检测 手动注册Bean
  • 双亲容器检测
  • 依赖初始化(递归)
  • 创建Bean createBean()
    protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {
        // 反正就是获取到真正beanName
        // 处理两个情况,1. 将别名转化成真的beanName;2. 把FactoryBean的前缀"&"给去了
        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        // 检测已经注册的Bean,保证不重复创建
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            // 这个方法还是有点逻辑的
            // 如果目前获得的sharedInstance 不是FactoryBean,那bean就赋值成sharedInstance,直接返回
            // 如果是FactoryBean就返回FactoryBean创建的实例,
            // 这个也是FactoryBean的知识点,我在我的另一篇文章也讲过了,
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // 直接翻译:创建过了此 beanName 的 prototype 类型的 bean,那么抛异常
            // We're assumably within a circular reference.
            // 往往是因为陷入了循环引用
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            // 检查下这个BeanDefinition是否存在
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                // 当前容器没有这个BeanDefinition,去parent 容器去找
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {
                // 这个 getMergedLocalBeanDefinition 前面讲过哦
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // 先初始化依赖的所有 Bean,这个很好理解。
                // 注意,这里的依赖指的是 depends-on 中定义的依赖
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            // 这里循环依赖概念不要紊乱了
                            // 这里指的是通过 depends-on 定义造成的循环依赖,
                            // 我们另外一种类成员式的循环引用Spring是支持的
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        // 注册依赖关系
                        // 这么做的原因是Spring在即将进行bean销毁的时候会【首先销毁被依赖的bean】。
                        // 看SpringBean的初始化和销毁顺序就知道了,依赖关系的保存目的就是这个
                        // 依赖关系的保存是通过一个ConcurrentHashMap<String, Set>完成的,key是bean的真实名字。
                        registerDependentBean(dep, beanName);
                        try {
                            // 先去初始化被依赖项
                            // 递归然后反递归回来
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // Create bean instance.
                // 如果是 singleton scope 的,创建 singleton 的实例
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                                // 创建Bean的详情,等下拉出来单独说
                                return createBean(beanName, mbd, args);
                            }
                            catch (BeansException ex) {
                                // Explicitly remove instance from singleton cache: It might have been put there
                                // eagerly by the creation process, to allow for circular reference resolution.
                                // Also remove any beans that received a temporary reference to the bean.
                                destroySingleton(beanName);
                                throw ex;
                            }
                        }
                    });
                    // 前面讲过了
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                // 如果是 prototype scope 的,创建 prototype 的实例
                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                // 如果不是 singleton 和 prototype 的话,需要委托给相应的实现类来处理
                // 这里非重点,我们的重点是singleton的创建
                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                beforePrototypeCreation(beanName);
                                try {
                                    return createBean(beanName, mbd, args);
                                }
                                finally {
                                    afterPrototypeCreation(beanName);
                                }
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // Check if required type matches the type of the actual bean instance.
        // 最后再检查下类型对不对,不对就抛异常了,对的话就返回
        if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
            try {
                return getTypeConverter().convertIfNecessary(bean, requiredType);
            }
            catch (TypeMismatchException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }

doCreateBean()

步骤概览:

  1. 开始是单例的话要先清除缓存;
  2. 实例化bean,将BeanDefinition转换为BeanWrapper;
  3. 使用MergedBeanDefinitionPostProcessor,Autowired注解就是通过此方法实现类型的预解析;
  4. 解决循环依赖问题;
  5. 填充属性,将属性填充到bean实例中;
  6. 注册DisposableBean;
  7. 创建完成并返回

三个关注点:

  1. createBeanInstance() 实例化
  2. populateBean(); 属性装配
  3. initializeBean() 处理Bean初始化之后的各种回调事件
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        // 这个BeanWrapper是创建出来持有对象的
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            // 如果是singleton,先把缓存中的同名bean消除
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) 
            // 关键代码,后面拉出来单独讲
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
        mbd.resolvedTargetType = beanType;

        // Allow post-processors to modify the merged bean definition.
        // 涉及接口:MergedBeanDefinitionPostProcessor
        // 不是关键逻辑,不讲了
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        // 这里是为了解决循环依赖的,先把初步实例化的Bean实例的引用缓存起来,暴露出去,
        // 这个可以结合别的文章学习,面试题常考,我后面可能也会写
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            // 时序图中的一步,关键步骤,属性装配,前面的实例只是实例化,没有装配属性
            // 和前面的createBeanInstance一样会拉出来讲,继续看下去吧
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                // 还记得 init-method 吗?还有 InitializingBean 接口?还有 BeanPostProcessor 接口?
                // 这里就是处理 bean 初始化完成后的各种回调
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }


        // 这个逻辑分支我一次性说完吧。
        // 如果该beanName对象已经注册单例模式,则从单例中获取,并判断获取到的bean实例(B)与BeanWrapper中的bean实例(A)是同一个实例,如果是,则返回A或者B,如果不是,则递归找出它的依赖bean。
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
             // earlySingletonReference只有在检测到有循环依赖的情况下才会不为空
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    // 两个是同一个引用,bean初始化完成
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        // 注册DisposableBean;
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

上一步的三个关注点,分开来讲。

1. createBeanInstance()

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        // Make sure bean class is actually resolved at this point.
        // 解析出 Class
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }

        // 如果工厂方法不为空,则是用工厂方法初始化
        if (mbd.getFactoryMethodName() != null)  {
            // 相关知识点看另一篇文章关于FactoryBean的
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // Shortcut when re-creating the same bean...
        // 如果不是第一次创建,比如第二次创建 prototype bean。
        // 这种情况下,我们可以从第一次创建知道,采用无参构造函数,还是构造函数依赖注入 来完成实例化
        // 所以注释说叫shortcut
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    // 有已经解析过的构造方法
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        // 如果已经解析过则使用解析好的构造方法不需要再次锁定
        if (resolved) {
            if (autowireNecessary) {
                // 构造方法自动注入
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                // 默认构造方法
                return instantiateBean(beanName, mbd);
            }
        }

        // Need to determine the constructor...
        // 判断是否采用有参构造函数
        // 构造器自动装配
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // No special handling: simply use no-arg constructor.
        // 使用无参构造器
        return instantiateBean(beanName, mbd);
    }

2. populateBean(); 属性装配

入口方法: AbstractAutowireCapableBeanFactory#populateBean

它的作用是: 根据autowire类型进行autowire by nameby type或者是直接进行设置

    protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        PropertyValues pvs = mbd.getPropertyValues();

        if (bw == null) {
            if (!pvs.isEmpty()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        // 这里看注解是一个扩展点 
        // InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改
        // 不是个常用的扩展点,这里不讲了
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            // Add property values based on autowire by name if applicable.
            // 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }

            // Add property values based on autowire by type if applicable.
            // 通过类型装配
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }

            pvs = newPvs;
        }

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        // InstantiationAwareBeanPostProcessor.postProcessPropertyValues方法
                        // 代表能对属性值进行修改的能力
                        // 其中一个很有用实现类提一下,AutowiredAnnotationBeanPostProcessor
                        // 对采用@Autowired和@Value设值的就是这个BeanPostProcessor干的。
                        // 不展开讲了,不然要讲不完了
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }
        // 这里才是设置bean实例的属性值
        applyPropertyValues(beanName, mbd, bw, pvs);
    }

3. initializeBean() 处理Bean初始化之后的各种回调事件

看这个方法的javadoc 描述

Initialize the given bean instance, applying factory callbacks as well as init methods and bean post processors.

    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, getAccessControlContext());
        }
        else {
            // 涉及到的回调接口点进去一目了然,代码都是自解释的
            // BeanNameAware、BeanClassLoaderAware或BeanFactoryAware
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor 的 postProcessBeforeInitialization 回调
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // init-methods
            // 或者是实现了InitializingBean接口,会调用afterPropertiesSet() 方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor 的 postProcessAfterInitialization 回调
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }

大家发现没有,BeanPostProcessor 的两个回调都发生在这边,只不过中间处理了 init-method。这和我原来的认知有点不一样了?因为Spring的源码中代码的命名很多时候是自解释的,很多时候我看英文就知道这些方法的意图,但在这里,为什么BeanPostProcessor的前置处理方法postProcessBeforeInitialization()也是在属性设置完成后调用的?

后面查询了去看英文的解释,

BeanPostProcessor is used to interact with newly created bean instances before and/or after their initialization method is invoked by the Spring container. You can use BeanPostProcessor to execute custom logic before and/or after bean’s initialization method is invoked by the Spring container.

BeanPostProcessor的意图就是在初始化方法的前后做定制化操作。仔细想想好像这个命名也没毛病。如果真的是在SpringBean实例化之前调用应该叫BeforeInstantiation。源码中的initialization指的就是上面的invokeInitMethods操作。

结语

以上,就是关于Spring IoC 依赖注入的主要内容。

Spring IoC 容器这里还有一些其他的知识点,有关于SpringIoC 特性的。比如,Spring bean的生命周期、FactoryBean、BeanPostProcessor,都是在使用Spring IoC 容器经常遇到的特性。在了解了IoC容器的整体运行原理以后,你应该能够对这些特性进行一些分析,将你使用这些特性的方法和源码结合起来,融会贯通。

至此,Spring IoC关于依赖注入的源码“大致”解读完毕,还是那句话,上面的源码解析,肯定不会是完备的,只是提取了我认为重要的东西。

如有疏漏,敬请谅解和自己查阅相关资料学习。如果错误,敬请指正!

本文由博客一文多发平台 OpenWrite 发布!

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

推荐阅读更多精彩内容