spring源碼筆記-instantiateUsingFactoryMethod與autowireConstructor兩個Bean實例化方法

基于springboot2.1.4

1蒸甜、instantiateUsingFactoryMethod

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod-->org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs)

         public BeanWrapper instantiateUsingFactoryMethod(
            String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

        BeanWrapperImpl bw = new BeanWrapperImpl();
        this.beanFactory.initBeanWrapper(bw);

        Object factoryBean;
        Class<?> factoryClass;
        boolean isStatic;
       // 通過beanDefinition獲取到factoryBeanName 懂牧,實際就是@Bean注解的方法
        //所在的configuration類
        String factoryBeanName = mbd.getFactoryBeanName();
        if (factoryBeanName != null) {
            if (factoryBeanName.equals(beanName)) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                        "factory-bean reference points back to the same bean definition");
            }
          //  獲取configuration類的實例
            factoryBean = this.beanFactory.getBean(factoryBeanName);
            if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
                throw new ImplicitlyAppearedSingletonException();
            }
            factoryClass = factoryBean.getClass();
            isStatic = false;
        }
        else {
            // It's a static factory method on the bean class.
            if (!mbd.hasBeanClass()) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                        "bean definition declares neither a bean class nor a factory-bean reference");
            }
            factoryBean = null;
            factoryClass = mbd.getBeanClass();
            isStatic = true;
        }

        Method factoryMethodToUse = null;
        ArgumentsHolder argsHolderToUse = null;
        Object[] argsToUse = null;

        //如果在調(diào)用getBean方法時有傳參琢锋,那就用傳的參作為
        //@Bean注解的方法(工廠方法)的參數(shù),
       // 一般懶加載的bean才會傳參,啟動過程就實例化的實際上都沒有傳參
        if (explicitArgs != null) {
            argsToUse = explicitArgs;
        }
        else {
            Object[] argsToResolve = null;
            synchronized (mbd.constructorArgumentLock) {
                factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
             //不為空表示已經(jīng)使用過工廠方法赶熟,現(xiàn)在是再次使用工廠方法领猾,
             //  一般原型模式和Scope模式采用的上米同,直接使用該工廠方法和緩存的參數(shù)
                if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
                    // Found a cached factory method...
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }
            if (argsToResolve != null) {
                argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
            }
        }

      //  調(diào)用getBean方法沒有傳參,同時也是第一次使用工廠方法
        if (factoryMethodToUse == null || argsToUse == null) {
            // Need to determine the factory method...
            // Try all methods with this name to see if they match the given arguments.
            factoryClass = ClassUtils.getUserClass(factoryClass);
       // 獲取configuration類的所有候選方法
            Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
            List<Method> candidateList = new ArrayList<>();
            for (Method candidate : rawCandidates) {
        // 查找到與工廠方法同名的候選方法,沒有@Bean的同名方法不被考慮
                if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
                    candidateList.add(candidate);
                }
            }

         //當(dāng)與工廠方法同名的候選方法只有一個摔竿,且調(diào)用getBean方法時沒有傳參面粮,
       //  且沒有緩存過參數(shù),直接通過調(diào)用實例化方法執(zhí)行該候選方法
            if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
                Method uniqueCandidate = candidateList.get(0);
                if (uniqueCandidate.getParameterCount() == 0) {
                    mbd.factoryMethodToIntrospect = uniqueCandidate;
                    synchronized (mbd.constructorArgumentLock) {
                        mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                        mbd.constructorArgumentsResolved = true;
                        mbd.resolvedConstructorArguments = EMPTY_ARGS;
                    }
                    bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
                    return bw;
                }
            }

            Method[] candidates = candidateList.toArray(new Method[0]);
     // 有多個與工廠方法同名的候選方法時继低,進行排序熬苍。public的方法會往前排,然后參數(shù)個數(shù)多的方法往前排
      //具體排序代碼--->org.springframework.beans.factory.support.AutowireUtils#sortConstructors

            ConstructorArgumentValues resolvedValues = null;
            boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
            int minTypeDiffWeight = Integer.MAX_VALUE;
            Set<Method> ambiguousFactoryMethods = null;

            int minNrOfArgs;
           // 如果調(diào)用getBean方法時有傳參袁翁,那么工廠方法最少參數(shù)個數(shù)要等于傳參個數(shù)
            if (explicitArgs != null) {
                minNrOfArgs = explicitArgs.length;
            }
            else {
                // We don't have arguments passed in programmatically, so we need to resolve the
                // arguments specified in the constructor arguments held in the bean definition.
                if (mbd.hasConstructorArgumentValues()) {
                    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                    resolvedValues = new ConstructorArgumentValues();
                    minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
                }
                else {
                    minNrOfArgs = 0;
                }
            }

            LinkedList<UnsatisfiedDependencyException> causes = null;
           // 遍歷同名候選方法
            for (Method candidate : candidates) {
             //   獲取候選方法的參數(shù)列表
                Class<?>[] paramTypes = candidate.getParameterTypes();

                if (paramTypes.length >= minNrOfArgs) {
                    ArgumentsHolder argsHolder;
                //在調(diào)用getBean方法時傳的參數(shù)不為空柴底,則工廠方法的參數(shù)個數(shù)需要與
               // 傳入的參數(shù)個數(shù)嚴格一致
                    if (explicitArgs != null) {
                        // Explicit arguments given -> arguments length must match exactly.
                        if (paramTypes.length != explicitArgs.length) {
                            continue;
                        }
                        argsHolder = new ArgumentsHolder(explicitArgs);
                    }
                    else {
                        // Resolved constructor arguments: type conversion and/or autowiring necessary.
                        try {
                            String[] paramNames = null;
                            ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                            if (pnd != null) {
                                paramNames = pnd.getParameterNames(candidate);
                            }
                     //當(dāng)傳入的參數(shù)為空,需要根據(jù)工廠方法的參數(shù)類型注入相應(yīng)的
                   //  bean梦裂。詳細的注入代碼可查看
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
                     //暫不過多解析似枕,如有需要再另外開篇記錄
                            argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                    paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
                        }
                        catch (UnsatisfiedDependencyException ex) {
                            if (logger.isTraceEnabled()) {
                                logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
                            }
                            // Swallow and try next overloaded factory method.
                            if (causes == null) {
                                causes = new LinkedList<>();
                            }
                            causes.add(ex);
                            continue;
                        }
                    }
           /**計算工廠方法的權(quán)重,分嚴格模式和寬松模式年柠,計算方式可以看本文最后的附錄
            嚴格模式會校驗子類(注入?yún)?shù))繼承了多少層父類(方法參數(shù))層數(shù)越多權(quán)重越大凿歼,越不匹配
            褪迟,寬松模式,只要是注入?yún)?shù)類型是方法參數(shù)類型的子類就行答憔。
            默認寬松模式 在argsHolders中會有arguments和rawArguments味赃,;
           例如在注入bean時虐拓,如果有經(jīng)歷過createArgumentArray方法中的TypeConverter
         (如有有定義并且注冊到beanFactory中)的心俗,arguments和rawArguments的值是不一樣的
           如果沒有經(jīng)過轉(zhuǎn)換,兩者是一樣的蓉驹。通過getBean傳入的參數(shù)兩者通常都是一樣的
           所以都是先將工廠方法的參數(shù)類型與arguments的比較城榛,不同則賦予最大權(quán)重值,
           相同則與rawArguments比較态兴,與rawArguments中的相同狠持,就會賦最大權(quán)重值-1024,
           不相同瞻润,則賦最大權(quán)重值-512喘垂,經(jīng)過類型轉(zhuǎn)換一定會執(zhí)行最大權(quán)重值-512的操作。
           權(quán)重值越大绍撞,該工廠方法越不匹配正勒。總的來說就是傳入的參數(shù)或者注入的參數(shù)類型
           與工廠方法參數(shù)類型的比對傻铣。**/
                    int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                            argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                    // Choose this factory method if it represents the closest match.
                    if (typeDiffWeight < minTypeDiffWeight) {
            /**  當(dāng)權(quán)重小時章贞,重新設(shè)置factoryMethodToUse 和argsHolderToUse ,argsToUse 矾柜,
              并把當(dāng)前權(quán)重值設(shè)置為最小權(quán)重值阱驾,等待遍歷的下一個候選工廠方法比對,
              并且將ambiguousFactoryMethods (表示有含糊同樣權(quán)重的候選方法)設(shè)置為空**/
                        factoryMethodToUse = candidate;
                        argsHolderToUse = argsHolder;
                        argsToUse = argsHolder.arguments;
                        minTypeDiffWeight = typeDiffWeight;
                        ambiguousFactoryMethods = null;
                    }
                    // Find out about ambiguity: In case of the same type difference weight
                    // for methods with the same number of parameters, collect such candidates
                    // and eventually raise an ambiguity exception.
                    // However, only perform that check in non-lenient constructor resolution mode,
                    // and explicitly ignore overridden methods (with the same parameter signature).
           /**  當(dāng)遍歷到下一個候選方法的時候怪蔑,已經(jīng)設(shè)置了factoryMethodToUse 且權(quán)重值
             與上一次的最小權(quán)重值相等時里覆,ambiguousFactoryMethods填值,這個ambiguousFactoryMethods不為空
             表示有兩個候選方法的最小權(quán)重相等缆瓣,spring無法匹配出最適合的工廠方法喧枷,
             如果再繼續(xù)往下遍歷候選器,有更小的權(quán)重值弓坞,那ambiguousFactoryMethods會
             再次被設(shè)置為空**/
                    else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
                            !mbd.isLenientConstructorResolution() &&
                            paramTypes.length == factoryMethodToUse.getParameterCount() &&
                            !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
                        if (ambiguousFactoryMethods == null) {
                            ambiguousFactoryMethods = new LinkedHashSet<>();
                            ambiguousFactoryMethods.add(factoryMethodToUse);
                        }
                        ambiguousFactoryMethods.add(candidate);
                    }
                }
            }

            if (factoryMethodToUse == null) {
                if (causes != null) {
                    UnsatisfiedDependencyException ex = causes.removeLast();
                    for (Exception cause : causes) {
                        this.beanFactory.onSuppressedException(cause);
                    }
                    throw ex;
                }
                List<String> argTypes = new ArrayList<>(minNrOfArgs);
                if (explicitArgs != null) {
                    for (Object arg : explicitArgs) {
                        argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
                    }
                }
                else if (resolvedValues != null) {
                    Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
                    valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
                    valueHolders.addAll(resolvedValues.getGenericArgumentValues());
                    for (ValueHolder value : valueHolders) {
                        String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
                                (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
                        argTypes.add(argType);
                    }
                }
                String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "No matching factory method found: " +
                        (mbd.getFactoryBeanName() != null ?
                            "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
                        "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
                        "Check that a method with the specified name " +
                        (minNrOfArgs > 0 ? "and arguments " : "") +
                        "exists and that it is " +
                        (isStatic ? "static" : "non-static") + ".");
            }
             //返回類型不能為void
            else if (void.class == factoryMethodToUse.getReturnType()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Invalid factory method '" + mbd.getFactoryMethodName() +
                        "': needs to have a non-void return type!");
            }
           //存在含糊的兩個工廠方法隧甚,不知選哪個
            else if (ambiguousFactoryMethods != null) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Ambiguous factory method matches found in bean '" + beanName + "' " +
                        "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
                        ambiguousFactoryMethods);
            }

            if (explicitArgs == null && argsHolderToUse != null) {
                mbd.factoryMethodToIntrospect = factoryMethodToUse;
                argsHolderToUse.storeCache(mbd, factoryMethodToUse);
            }
        }

        Assert.state(argsToUse != null, "Unresolved factory method arguments");
     //   到達這里,恭喜渡冻,可以完成實例化了
        bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
        return bw;
    }

看下例子

        @Bean
        public String getStr20(){
            System.out.println("helloTest in HelloConfigurationInner20");
            return "helloTest";
        }
        @Bean
        public Executor  getStr20(Executor executor){
            System.out.println("helloTest in HelloConfigurationInner20");
            return executor;
        }
//        兩者參數(shù)個數(shù)一樣多戚扳,權(quán)重也一樣,兩者的參數(shù)都不是通過轉(zhuǎn)換類型得來的族吻,無法判斷哪個才是被選召的孩子
//        @Bean
//        public String getStr20(OrderBean hello){
//            System.out.println("helloTest in HelloConfigurationInner20");
//            return "helloTest"+hello;
//        }
2帽借、autowireConstructor

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor--->org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs)
構(gòu)造器方法的過程有很多跟工廠方法相似的地方珠增,比如,傳入?yún)?shù)的處理砍艾,候選方法的排序蒂教,參數(shù)的注入,權(quán)重計算等梦皮。不同的是instantiateUsingFactoryMethod有factoryBean的查找覆旭,重要的邏輯基本差不多,就不重復(fù)記錄了七兜,重點說下在調(diào)用autowireConstructor前就要先獲取到構(gòu)造器腕铸,并作為參數(shù)傳入,重點來關(guān)注spring默認的獲取構(gòu)造方法的邏輯
進入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance-->org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors遍歷所有的SmartInstantiationAwareBeanPostProcessor實例狠裹,執(zhí)行其determineCandidateConstructors方法(如有需要可以自定義SmartInstantiationAwareBeanPostProcessor撇吞,按需求重寫determineCandidateConstructors方法)默認的processor為AutowiredAnnotationBeanPostProcessor接著進入org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors看關(guān)鍵部分

//如果之前已經(jīng)有用構(gòu)造方法實例化bean,就會有緩存死姚,原型模式和scope模式會有再次使用的時候
        // Quick check on the concurrent map first, with minimal locking.
        Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
        if (candidateConstructors == null) {
            // Fully synchronized resolution now...
            synchronized (this.candidateConstructorsCache) {
                candidateConstructors = this.candidateConstructorsCache.get(beanClass);
                if (candidateConstructors == null) {
                    Constructor<?>[] rawCandidates;
                    try {
//緩存中不存在的時候使用getDeclaredConstructors方法獲取所有的構(gòu)造方法
                        rawCandidates = beanClass.getDeclaredConstructors();
                    }
                    catch (Throwable ex) {
                        throw new BeanCreationException(beanName,
                                "Resolution of declared constructors on bean Class [" + beanClass.getName() +
                                "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
                    }
                    List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                    Constructor<?> requiredConstructor = null;
                    Constructor<?> defaultConstructor = null;
//優(yōu)先的構(gòu)造方法是從kotlin文件獲取,沒玩過kotlin,不知道怎么弄瀑焦,先不管
                    Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                    int nonSyntheticConstructors = 0;
                    for (Constructor<?> candidate : rawCandidates) {
                        if (!candidate.isSynthetic()) {
                            nonSyntheticConstructors++;
                        }
                        else if (primaryConstructor != null) {
                            continue;
                        }
//查找是否有@Autowired注解
                        AnnotationAttributes ann = findAutowiredAnnotation(candidate);
                        if (ann == null) {
//如果沒有@Autowired注解,查找父類的構(gòu)造方法有沒有@Autowired注解
                            Class<?> userClass = ClassUtils.getUserClass(beanClass);
                            if (userClass != beanClass) {
                                try {
                                    Constructor<?> superCtor =
                                            userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                    ann = findAutowiredAnnotation(superCtor);
                                }
                                catch (NoSuchMethodException ex) {
                                    // Simply proceed, no equivalent superclass constructor found...
                                }
                            }
                        }
                        if (ann != null) {
            //  當(dāng)@Autowired注解的構(gòu)造方法不止一個,那上一次處理的候選構(gòu)造方法
         //     已經(jīng)設(shè)置到requiredConstructor 中粹懒,那么第二個@Autowired注解的
             // 候選構(gòu)造方法處理的時候就會拋異常
                            if (requiredConstructor != null) {
                                throw new BeanCreationException(beanName,
                                        "Invalid autowire-marked constructor: " + candidate +
                                        ". Found constructor with 'required' Autowired annotation already: " +
                                        requiredConstructor);
                            }
                            boolean required = determineRequiredStatus(ann);
                            if (required) {
                                if (!candidates.isEmpty()) {
                                    throw new BeanCreationException(beanName,
                                            "Invalid autowire-marked constructors: " + candidates +
                                            ". Found constructor with 'required' Autowired annotation: " +
                                            candidate);
                                }
//第一個處理的有@autowired處理的構(gòu)造方法設(shè)置requiredConstructor 弓颈,并設(shè)置到candidates中
                                requiredConstructor = candidate;
                            }
                            candidates.add(candidate);
                        }
//當(dāng)構(gòu)造方法沒有@Autowired注解且參數(shù)個數(shù)為0橘蜜,選為defaultConstructor 
                        else if (candidate.getParameterCount() == 0) {
                            defaultConstructor = candidate;
                        }
                    }
                    if (!candidates.isEmpty()) {
                        // Add default constructor to list of optional constructors, as fallback.
                        if (requiredConstructor == null) {
                            if (defaultConstructor != null) {
//往候選方法中加入defaultConstructor
//(好像requiredConstructor 為null象颖,candidates就會為null潮瓶,感覺此句永遠不會執(zhí)行)
                                candidates.add(defaultConstructor);
                            }
                            else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                                logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
                                        "': single autowire-marked constructor flagged as optional - " +
                                        "this constructor is effectively required since there is no " +
                                        "default constructor to fall back to: " + candidates.get(0));
                            }
                        }
//候選方法不為空的時候進入此處,此時就一個@Autowired注解的構(gòu)造方法
                        candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                    }
//當(dāng)獲取的所有構(gòu)造方法只有一個思恐,且不是@autowired注解的(注解的在上面處理了)
//且參數(shù)在一個以上栅螟,該方法作為候選的構(gòu)造方法
                    else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                        candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
                    }
//后面primaryConstructor 的都不看了
                    else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                            defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                        candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
                    }
                    else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                        candidateConstructors = new Constructor<?>[] {primaryConstructor};
                    }
                    else {
                        candidateConstructors = new Constructor<?>[0];
                    }
//緩存選定的候選構(gòu)造方法搪哪,供原型模式和scope模式第二次實例化時使用
                    this.candidateConstructorsCache.put(beanClass, candidateConstructors);
                }
            }
        }
返回選定的構(gòu)造函數(shù)列表
        return (candidateConstructors.length > 0 ? candidateConstructors : null);

上demo

/**首先永遠不必理會無參構(gòu)造方法,他最后都是不會通過autowireConstructor方法實例化坪圾,
如果只有一個帶參構(gòu)造方法晓折,那他就被選擇為候選構(gòu)造方法,如果有多個帶參構(gòu)造方法兽泄,
則需要通過@Autowired注解其中一個漓概,不能有多個@Autowired注解的構(gòu)造方法**/

  //  public TestService(){}
//    @Autowired
    public TestService(OrderBean orderBean) {
        this.orderBean = orderBean;
    }


//    @Autowired
//    public TestService(Executor executor,OrderBean orderBean){}


關(guān)于權(quán)重值的計算

關(guān)于候選方法排序
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市病梢,隨后出現(xiàn)的幾起案子胃珍,更是在濱河造成了極大的恐慌,老刑警劉巖蜓陌,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件觅彰,死亡現(xiàn)場離奇詭異,居然都是意外死亡钮热,警方通過查閱死者的電腦和手機填抬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隧期,“玉大人飒责,你說我怎么就攤上這事赘娄。” “怎么了宏蛉?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵遣臼,是天一觀的道長。 經(jīng)常有香客問我拾并,道長暑诸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任辟灰,我火速辦了婚禮个榕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芥喇。我一直安慰自己西采,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布继控。 她就那樣靜靜地躺著械馆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪武通。 梳的紋絲不亂的頭發(fā)上霹崎,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音冶忱,去河邊找鬼尾菇。 笑死,一個胖子當(dāng)著我的面吹牛囚枪,可吹牛的內(nèi)容都是我干的派诬。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼链沼,長吁一口氣:“原來是場噩夢啊……” “哼默赂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起括勺,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤缆八,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后疾捍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奈辰,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年拾氓,在試婚紗的時候發(fā)現(xiàn)自己被綠了冯挎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖房官,靈堂內(nèi)的尸體忽然破棺而出趾徽,到底是詐尸還是另有隱情,我是刑警寧澤翰守,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布孵奶,位于F島的核電站,受9級特大地震影響蜡峰,放射性物質(zhì)發(fā)生泄漏了袁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一湿颅、第九天 我趴在偏房一處隱蔽的房頂上張望载绿。 院中可真熱鬧,春花似錦油航、人聲如沸崭庸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怕享。三九已至,卻和暖如春镰踏,著一層夾襖步出監(jiān)牢的瞬間函筋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工奠伪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留跌帐,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓芳来,卻偏偏與公主長得像含末,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子即舌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

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