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;

        //如果在调用getBean方法时有传参,那就用传的参作为
        //@Bean注解的方法(工厂方法)的参数,
       // 一般懒加载的bean才会传参,启动过程就实例化的实际上都没有传参
        if (explicitArgs != null) {
            argsToUse = explicitArgs;
        }
        else {
            Object[] argsToResolve = null;
            synchronized (mbd.constructorArgumentLock) {
                factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
             //不为空表示已经使用过工厂方法,现在是再次使用工厂方法,
             //  一般原型模式和Scope模式采用的上,直接使用该工厂方法和缓存的参数
                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);
            }
        }

      //  调用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);
                }
            }

         //当与工厂方法同名的候选方法只有一个,且调用getBean方法时没有传参,
       //  且没有缓存过参数,直接通过调用实例化方法执行该候选方法
            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的方法会往前排,然后参数个数多的方法往前排
      //具体排序代码--->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;
           // 如果调用getBean方法时有传参,那么工厂方法最少参数个数要等于传参个数
            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) {
             //   获取候选方法的参数列表
                Class<?>[] paramTypes = candidate.getParameterTypes();

                if (paramTypes.length >= minNrOfArgs) {
                    ArgumentsHolder argsHolder;
                //在调用getBean方法时传的参数不为空,则工厂方法的参数个数需要与
               // 传入的参数个数严格一致
                    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);
                            }
                     //当传入的参数为空,需要根据工厂方法的参数类型注入相应的
                   //  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;
                        }
                    }
           /**计算工厂方法的权重,分严格模式和宽松模式,计算方式可以看本文最后的附录
            严格模式会校验子类(注入参数)继承了多少层父类(方法参数)层数越多权重越大,越不匹配
            ,宽松模式,只要是注入参数类型是方法参数类型的子类就行。
            默认宽松模式 在argsHolders中会有arguments和rawArguments,;
           例如在注入bean时,如果有经历过createArgumentArray方法中的TypeConverter
         (如有有定义并且注册到beanFactory中)的,arguments和rawArguments的值是不一样的
           如果没有经过转换,两者是一样的。通过getBean传入的参数两者通常都是一样的
           所以都是先将工厂方法的参数类型与arguments的比较,不同则赋予最大权重值,
           相同则与rawArguments比较,与rawArguments中的相同,就会赋最大权重值-1024,
           不相同,则赋最大权重值-512,经过类型转换一定会执行最大权重值-512的操作。
           权重值越大,该工厂方法越不匹配。总的来说就是传入的参数或者注入的参数类型
           与工厂方法参数类型的比对。**/
                    int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                            argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                    // Choose this factory method if it represents the closest match.
                    if (typeDiffWeight < minTypeDiffWeight) {
            /**  当权重小时,重新设置factoryMethodToUse 和argsHolderToUse ,argsToUse ,
              并把当前权重值设置为最小权重值,等待遍历的下一个候选工厂方法比对,
              并且将ambiguousFactoryMethods (表示有含糊同样权重的候选方法)设置为空**/
                        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).
           /**  当遍历到下一个候选方法的时候,已经设置了factoryMethodToUse 且权重值
             与上一次的最小权重值相等时,ambiguousFactoryMethods填值,这个ambiguousFactoryMethods不为空
             表示有两个候选方法的最小权重相等,spring无法匹配出最适合的工厂方法,
             如果再继续往下遍历候选器,有更小的权重值,那ambiguousFactoryMethods会
             再次被设置为空**/
                    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;
        }
//        两者参数个数一样多,权重也一样,两者的参数都不是通过转换类型得来的,无法判断哪个才是被选召的孩子
//        @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)
构造器方法的过程有很多跟工厂方法相似的地方,比如,传入参数的处理,候选方法的排序,参数的注入,权重计算等。不同的是instantiateUsingFactoryMethod有factoryBean的查找,重要的逻辑基本差不多,就不重复记录了,重点说下在调用autowireConstructor前就要先获取到构造器,并作为参数传入,重点来关注spring默认的获取构造方法的逻辑
进入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance-->org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors遍历所有的SmartInstantiationAwareBeanPostProcessor实例,执行其determineCandidateConstructors方法(如有需要可以自定义SmartInstantiationAwareBeanPostProcessor,按需求重写determineCandidateConstructors方法)默认的processor为AutowiredAnnotationBeanPostProcessor接着进入org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors看关键部分

//如果之前已经有用构造方法实例化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方法获取所有的构造方法
                        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;
//优先的构造方法是从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注解,查找父类的构造方法有没有@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) {
            //  当@Autowired注解的构造方法不止一个,那上一次处理的候选构造方法
         //     已经设置到requiredConstructor 中,那么第二个@Autowired注解的
             // 候选构造方法处理的时候就会抛异常
                            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处理的构造方法设置requiredConstructor ,并设置到candidates中
                                requiredConstructor = candidate;
                            }
                            candidates.add(candidate);
                        }
//当构造方法没有@Autowired注解且参数个数为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,感觉此句永远不会执行)
                                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注解的构造方法
                        candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                    }
//当获取的所有构造方法只有一个,且不是@autowired注解的(注解的在上面处理了)
//且参数在一个以上,该方法作为候选的构造方法
                    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];
                    }
//缓存选定的候选构造方法,供原型模式和scope模式第二次实例化时使用
                    this.candidateConstructorsCache.put(beanClass, candidateConstructors);
                }
            }
        }
返回选定的构造函数列表
        return (candidateConstructors.length > 0 ? candidateConstructors : null);

上demo

/**首先永远不必理会无参构造方法,他最后都是不会通过autowireConstructor方法实例化,
如果只有一个带参构造方法,那他就被选择为候选构造方法,如果有多个带参构造方法,
则需要通过@Autowired注解其中一个,不能有多个@Autowired注解的构造方法**/

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


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


关于权重值的计算

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

推荐阅读更多精彩内容