BeanDefinition 在IOC的解析和注冊(cè)

概述

前面我們介紹了BeanDefinition的載入和解析的過(guò)程,將我們定義好的Bean資源文件載入并轉(zhuǎn)換成了Document對(duì)象迫像,然后Document對(duì)象通過(guò)BeanDefinitionDocumentReader來(lái)解析在旱,這些動(dòng)作完成以后貌矿,用戶自定義的BeanDefinition信息已經(jīng)在IOC容器內(nèi)建立起了自己的數(shù)據(jù)結(jié)構(gòu)雷蹂,以及相應(yīng)的數(shù)據(jù)表示姆怪,但這些數(shù)據(jù)還不能在IOC容器中直接使用也物,需要在IOC容器中對(duì)這些BeanDefinition進(jìn)行注冊(cè)宫屠。這個(gè)注冊(cè)為IOC容器提供了更友好的使用方式。在DefaultListableBeanDactory中是使用一個(gè)Map對(duì)象載入并持有這些BeanDefinition的滑蚯,代碼如下所示:

    /** Map of bean definition objects, keyed by bean name. */
    /**持有BeanDefinition的map容器**/
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
源碼解析

1.核心流程時(shí)序圖:

核心流程時(shí)序圖

從源碼實(shí)現(xiàn)的角度我們可以分析得到上圖的調(diào)用關(guān)系浪蹂。我們可以跟蹤源碼具體看一下注冊(cè)實(shí)現(xiàn)抵栈,在DefaultListableBeanFactory中實(shí)現(xiàn)了BeanDefinitionRegistry的接口,這個(gè)接口的實(shí)現(xiàn)完成了BeanDefinition向容器注冊(cè)坤次。注冊(cè)過(guò)程就是將解析得到的BeanDefinition設(shè)置到Map中去古劲,但是如果遇到同名的BeanDefinition,進(jìn)行處理的時(shí)候需要依據(jù)allowBeanDefinitionOverriding的配置來(lái)完成缰猴。下面我們就BeanDefinition的注冊(cè)邏輯展開(kāi)分析产艾。

2.源代碼分析

  • registerBeanDefinitions核心流程代碼解析:

    
    /**
     * 通過(guò)解析Document解析注冊(cè)BeanDefinition
     * Register the bean definitions contained in the given DOM document.
     * Called by {@code loadBeanDefinitions}.
     * <p>Creates a new instance of the parser class and invokes
     * {@code registerBeanDefinitions} on it.
     * @param doc the DOM document
     * @param resource the resource descriptor (for context information)
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of parsing errors
     * @see #loadBeanDefinitions
     * @see #setDocumentReaderClass
     * @see BeanDefinitionDocumentReader#registerBeanDefinitions
     */
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 獲取BeanDefinition的Document解析器
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        // 獲取已經(jīng)注冊(cè)的BeanDefinition的個(gè)數(shù)
        int countBefore = getRegistry().getBeanDefinitionCount();
        // 創(chuàng)建XmlRederContext,解析Document并注冊(cè)BeanDefinition
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        // 計(jì)算新注冊(cè)的BeanDefinition的數(shù)量
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    
  • registerBeanDefinitions的處理邏輯解析:

    /**
     * This implementation parses bean definitions according to the "spring-beans" XSD (or DTD, historically).
     * document中element的解析并注冊(cè)BeanDefinition·
     * <p>Opens a DOM Document; then initializes the default settings
     * specified at the {@code <beans/>} level; then parses the contained bean definitions.
     */
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    
  • doRegisterBeanDefinitions處理邏輯解析

    
    /**
     * Register each bean definition within the given root {@code <beans/>} element.
     */
    @SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // 從<beans />配置中注冊(cè)每一個(gè)bean滑绒,如果有嵌套的beans闷堡,那么遞歸執(zhí)行這個(gè)方法。
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        // 在遞歸的時(shí)候疑故,跟蹤父級(jí)delegate杠览,新的遞歸調(diào)用引用上個(gè)方法的delegate
        BeanDefinitionParserDelegate parent = this.delegate;
        //  創(chuàng)建 BeanDefinitionParserDelegate 對(duì)象,并進(jìn)行設(shè)置到 delegate
        this.delegate = createDelegate(getReaderContext(), root, parent);
        // 檢查 <beans /> 根標(biāo)簽的命名空間是否為空纵势,或者是 http://www.springframework.org/schema/beans【1】
        if (this.delegate.isDefaultNamespace(root)) {
            // 處理 profile 屬性踱阿。可參見(jiàn)《Spring3自定義環(huán)境配置 <beans profile="">》 【2】
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                // 判定環(huán)境參數(shù)是否滿足钦铁,無(wú)效則不注冊(cè)
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }
        // 解析前處理目前是空處理软舌,可以繼承,由子類(lèi)去實(shí)現(xiàn)
        preProcessXml(root);
        // 解析xml為BeanDefinition并向容器注冊(cè)生成的BeanDefinition【3】
        parseBeanDefinitions(root, this.delegate);
        // 解析后處理,目前為空?qǐng)?zhí)行牛曹,子類(lèi)可繼承處理
        postProcessXml(root);
        // 設(shè)置為最初的BeanDefinitionParserDelegate
        this.delegate = parent;
    }
    

    【1】 檢查<beans /> 根標(biāo)簽的命名空間是否為空葫隙,或者是 http://www.springframework.org/schema/beans
    【2】檢查beans標(biāo)簽的是否指定profile環(huán)境注冊(cè),若profile參數(shù)是不滿足條件躏仇,則不注冊(cè)
    【3】解析element(<beans />)下的<bean/>元素并注冊(cè)到BeanDefinition的map容器中恋脚。
    說(shuō)明:createDelegate方法執(zhí)行主要是創(chuàng)建代理,然后代理首先初始化一些默認(rèn)的屬性焰手,DocumentDefaultsDefinition是存儲(chǔ)默認(rèn)配置的對(duì)象:default-lazy-init糟描、default-mergedefault-autowire书妻、default-dependency-check船响、default-autowire-candidatesdefault-init-method躲履、default-destroy-method见间。

  • parseBeanDefinitions處理邏輯解析

    /**
     * Parse the elements at the root level in the document: "import", "alias", "bean".
     *
     * @param root the DOM root element of the document
     */
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        // 如果該節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析【1】
        if (delegate.isDefaultNamespace(root)) {
            // root節(jié)點(diǎn)下的子節(jié)點(diǎn)【2】
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    // 如果該節(jié)點(diǎn)使用默認(rèn)命名空間工猜,執(zhí)行默認(rèn)解析【3】
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    } else { // 如果該節(jié)點(diǎn)非默認(rèn)命名空間米诉,執(zhí)行自定義解析【4】
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {// 如果根節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析【5】
            delegate.parseCustomElement(root);
        }
    }
    

    【1】如果該節(jié)點(diǎn)使用默認(rèn)命名空間篷帅,執(zhí)行默認(rèn)解析
    【2】root節(jié)點(diǎn)下的子節(jié)點(diǎn)
    【3】如果該節(jié)點(diǎn)使用默認(rèn)命名空間史侣,執(zhí)行默認(rèn)解析
    【4】如果該節(jié)點(diǎn)非默認(rèn)命名空間拴泌,執(zhí)行自定義解析
    【5】如果該節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析

  • parseDefaultElement處理邏輯解析

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        // import標(biāo)簽
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
            //  alias 解析
        } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
            //bean 解析
        } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
            // beans元素解析
        } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            //遞歸解析beans
            doRegisterBeanDefinitions(ele);
        }
    }
    
  • processBeanDefinition處理邏輯解析

    /**
     * Process the given bean element, parsing the bean definition and registering it with the registry.
     */
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 委托BeanDefinition類(lèi)的parseBeanDefinitionElement方法進(jìn)行元素解析,返回Beandefinition 【1】
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            // 當(dāng)返回的bdHolder 不為空的情況下,若存在默認(rèn)標(biāo)簽的子節(jié)點(diǎn)下再有自定義屬性,還需要再次對(duì)自定義標(biāo)簽進(jìn)行解析.【2】
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                // 最終執(zhí)行注冊(cè)邏輯【3】
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            // 下發(fā)注冊(cè)事件惊橱,通知相關(guān)的監(jiān)聽(tīng)器蚪腐,這個(gè)bean已經(jīng)加載完成【4】
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
    

    【1】委托BeanDefinition類(lèi)的parseBeanDefinitionElement方法進(jìn)行元素解析,返回Beandefinition ,此時(shí)的bdHolder實(shí)例已經(jīng)包含了我們配置文件中的各種屬性了,例如 : class,name,id,alias
    【2】當(dāng)返回的bdHolder 不為空的情況下,若存在默認(rèn)標(biāo)簽的子節(jié)點(diǎn)下再有自定義屬性,還需要再次對(duì)自定義標(biāo)簽進(jìn)行解析.
    【3】最終執(zhí)行BeanDefinition注冊(cè)邏輯
    【4】下發(fā)注冊(cè)事件税朴,通知相關(guān)的監(jiān)聽(tīng)器回季,這個(gè)bean已經(jīng)加載完成

  • registryBeanDefinition的注冊(cè)邏輯分析

    從代碼上分析我們的registryBeanDefinition的最終執(zhí)行是在是通過(guò)public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry),注冊(cè)的過(guò)程是在解析xml過(guò)程中完成注冊(cè)邏輯的正林。

    //---------------------------------------------------------------------
    // Implementation of BeanDefinitionRegistry interface
    //---------------------------------------------------------------------
    // 注冊(cè)BeanDefinition
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
           throws BeanDefinitionStoreException {
       // 校驗(yàn) beanName 與 beanDefinition 非空
       Assert.hasText(beanName, "Bean name must not be empty");
       Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
       if (beanDefinition instanceof AbstractBeanDefinition) {
           try {
               // 【1】 校驗(yàn)BeanDefinition泡一,這也是注冊(cè)前的最后一次校驗(yàn)了,主要是對(duì)屬性 methodOverrides 進(jìn)行校驗(yàn)卓囚。
               ((AbstractBeanDefinition) beanDefinition).validate();
           } catch (BeanDefinitionValidationException ex) {
               throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                       "Validation of bean definition failed", ex);
           }
       }
       //【2】從緩存中獲取指定beanName的 BeanDefinition,主要 判斷bean name下是否已經(jīng)注冊(cè)過(guò)BeanDefinition
       BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
       //【3】如果改BenDefinition已經(jīng)注冊(cè)诅病,如果不允許覆蓋的話哪亿,則拋出異常
       if (existingDefinition != null) {
           if (!isAllowBeanDefinitionOverriding()) {
               throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
           }
           // 當(dāng)前要注冊(cè)的BeanDefinition的role 大于 已經(jīng)注冊(cè)過(guò)的BeanDefinition 打印info 日志
           else if (existingDefinition.getRole() < beanDefinition.getRole()) {
               // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
               if (logger.isInfoEnabled()) {
                   logger.info("Overriding user-defined bean definition for bean '" + beanName +
                           "' with a framework-generated bean definition: replacing [" +
                           existingDefinition + "] with [" + beanDefinition + "]");
               }
           }
           // 當(dāng)前要注冊(cè)的BeanDefinition與已被覆蓋的BeanDefinition不是一個(gè)對(duì)象,打印Debug日志信息
           else if (!beanDefinition.equals(existingDefinition)) {
               if (logger.isDebugEnabled()) {
                   logger.debug("Overriding bean definition for bean '" + beanName +
                           "' with a different definition: replacing [" + existingDefinition +
                           "] with [" + beanDefinition + "]");
               }
           }
           // 打印 trace日志信息
           else {
               if (logger.isTraceEnabled()) {
                   logger.trace("Overriding bean definition for bean '" + beanName +
                           "' with an equivalent definition: replacing [" + existingDefinition +
                           "] with [" + beanDefinition + "]");
               }
           }
           // 覆蓋已經(jīng)注冊(cè)的bean信息
           this.beanDefinitionMap.put(beanName, beanDefinition);
       }
       // 【4】未注冊(cè)執(zhí)行注冊(cè)邏輯
       else {
           // 判斷Bean的創(chuàng)建階段是否已經(jīng)開(kāi)啟贤笆,開(kāi)啟的話需要對(duì)beanDefinitionMap進(jìn)行線程保護(hù)
           if (hasBeanCreationStarted()) {
               // Cannot modify startup-time collection elements anymore (for stable iteration)
               // beanDefinitionMap為全局變量蝇棉,加鎖保護(hù),防止創(chuàng)建階段和注冊(cè)階段的并發(fā)問(wèn)題
               synchronized (this.beanDefinitionMap) {
                   // 添加到BeanDefinition的map 容器中
                   this.beanDefinitionMap.put(beanName, beanDefinition);
                   // 添加BeanName到 beanDefinitionNames中去(beanDefinitionNames初始化限制了大小為256芥永,所以變更的時(shí)候需要引入一個(gè)中間變量-主要是擴(kuò)容問(wèn)題)
                   List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                   // 更新最新的beanDefinitionNames
                   updatedDefinitions.addAll(this.beanDefinitionNames);
                   updatedDefinitions.add(beanName);
                   this.beanDefinitionNames = updatedDefinitions;
                   // 從 manualSingletonNames 移除 beanName
                   removeManualSingletonName(beanName);
               }
           } else {
               // Still in startup registration phase
               // 添加到 BeanDefinition 到 beanDefinitionMap 中篡殷。
               this.beanDefinitionMap.put(beanName, beanDefinition);
               // 添加 beanName 到 beanDefinitionNames 中
               this.beanDefinitionNames.add(beanName);
               //  從 manualSingletonNames 移除 beanName
               removeManualSingletonName(beanName);
           }
           this.frozenBeanDefinitionNames = null;
       }
       // 【5】重新設(shè)置beanName對(duì)應(yīng)的緩存
       if (existingDefinition != null || containsSingleton(beanName)) {
           resetBeanDefinition(beanName);
       }
    }
    
    

    【1】對(duì)BeanDefinition進(jìn)行校驗(yàn),這也是注冊(cè)過(guò)程中最后一次校驗(yàn)了埋涧,主要是針對(duì)AbstractBeanDefinitionmethodOverride屬性進(jìn)行校驗(yàn)板辽。
    【2】根據(jù)beanName從緩存中獲取BeanDefinition。
    【3】如果緩存中已經(jīng)存在棘催,則根據(jù)allowBeanDefinitionOverriding標(biāo)簽判斷是否允許覆蓋劲弦,如果不允許覆蓋,則拋出BeanDefinitionStoreException異常醇坝。
    【4】若緩存中沒(méi)有beanName 的BeanDefinition對(duì)象邑跪,則判斷當(dāng)前階段是否已經(jīng)開(kāi)始了Bean的創(chuàng)建階段,如果是則對(duì)僅限并發(fā)保護(hù)呼猪,對(duì)BeanDefinitionMap進(jìn)行加鎖并發(fā)控制画畅。否則直接設(shè)置即可。
    【5】若緩存存在改beanName或者單例bean集合中存在該beanName宋距,則調(diào)用#resetBeanDefinition(beanName)方法轴踱,充值BeanDefinition緩存。

    整個(gè)階段的核心流程其實(shí)就是對(duì)beanDefinitionMap的操作谚赎,只要核心在于this.beanDefinitionMap.put(beanName, beanDefinition)方法寇僧,而B(niǎo)eanDefinition的存儲(chǔ)其實(shí)就是定義了個(gè)map摊腋,key為beanName,value為BeanDefinition嘁傀。

小結(jié)
BeanDefinition解析注冊(cè)詳細(xì)流程圖

微信公眾號(hào)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兴蒸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子细办,更是在濱河造成了極大的恐慌橙凳,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笑撞,死亡現(xiàn)場(chǎng)離奇詭異岛啸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)茴肥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)坚踩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瓤狐,你說(shuō)我怎么就攤上這事瞬铸。” “怎么了础锐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵嗓节,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我皆警,道長(zhǎng)拦宣,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任信姓,我火速辦了婚禮鸵隧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘意推。我一直安慰自己掰派,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布左痢。 她就那樣靜靜地躺著靡羡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俊性。 梳的紋絲不亂的頭發(fā)上略步,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音定页,去河邊找鬼趟薄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛典徊,可吹牛的內(nèi)容都是我干的杭煎。 我是一名探鬼主播恩够,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼羡铲!你這毒婦竟也來(lái)了蜂桶?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤也切,失蹤者是張志新(化名)和其女友劉穎扑媚,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體雷恃,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疆股,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了倒槐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旬痹。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖讨越,靈堂內(nèi)的尸體忽然破棺而出两残,到底是詐尸還是另有隱情,我是刑警寧澤谎痢,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布磕昼,位于F島的核電站卷雕,受9級(jí)特大地震影響节猿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜漫雕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一滨嘱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浸间,春花似錦拒逮、人聲如沸讯檐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泣棋。三九已至,卻和暖如春钥组,著一層夾襖步出監(jiān)牢的瞬間撼嗓,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工细移, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搏予,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓弧轧,卻偏偏與公主長(zhǎng)得像雪侥,于是被迫代替她去往敵國(guó)和親碗殷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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