spring循環(huán)依賴(lài)

引言

假如有class A;class B闪彼。其中A依賴(lài)B,B依賴(lài)A洲劣。那么在創(chuàng)建對(duì)象時(shí)就會(huì)有循環(huán)依賴(lài)的問(wèn)題备蚓,Spring是如何解決這個(gè)問(wèn)題的呢?如果這個(gè)依賴(lài)是在構(gòu)造器中囱稽,spring還可以解決循環(huán)依賴(lài)的問(wèn)題嗎郊尝?

@Component
public class A {

    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired
    private A a;
}

一、單例field屬性的循環(huán)依賴(lài)

這一節(jié)比較長(zhǎng)战惊,但很重要流昏。?
首先,我們需要單步調(diào)試代碼吞获,幫助我們更方便的了解spring的方法調(diào)用關(guān)系况凉。這一步可參考下述代碼:

public class TestMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext aac = new AnnotationConfigApplicationContext(TestMain.class);
        aac.getBean("a");
    }
}

?我們通過(guò)單步調(diào)試,可以跟蹤到獲取bean的核心方法:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 1 singletonObjects各拷,存儲(chǔ)成熟的完整bean對(duì)象
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                // 2 earlySingletonObjects 存儲(chǔ)早期對(duì)象刁绒,早期對(duì)象初始化不完全
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    // 3 singletonFactories 存儲(chǔ)bean工廠(chǎng),解決有后置處理器的bean烤黍,找到其最終對(duì)象的factory
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }

? 上述代碼中有三個(gè)緩存map知市,分別存儲(chǔ)不同時(shí)期的對(duì)象傻盟。

  • singletonObjects存儲(chǔ)完整的bean,bean完全創(chuàng)建完成嫂丙,將其放入singletonObjects娘赴。獲取bean也先由這里獲取。
  • earlySingletonObjects存儲(chǔ)早期對(duì)象跟啤,該早期對(duì)象中存在不可用的屬性值诽表。
  • singletonFactories存儲(chǔ)bean工廠(chǎng)對(duì)象,是經(jīng)過(guò)AOP增強(qiáng)的最終工廠(chǎng)對(duì)象隅肥。

? 上述代碼中竿奏,我們看到有三級(jí)緩存,這是解決循環(huán)依賴(lài)的關(guān)鍵武福。簡(jiǎn)單看下getSingleton做了以下幾件事:查詢(xún)一級(jí)緩存singletonObjects议双,然后查詢(xún)二級(jí)緩存earlySingletonObjects痘番,最后查詢(xún)?nèi)?jí)緩存singletonFactory捉片,同時(shí)將bean放到二級(jí)緩存,并由三級(jí)緩存清除汞舱。
但是這里對(duì)一個(gè)全新的bean伍纫,返回還是null,而且各級(jí)緩存中的對(duì)象是什么時(shí)候放進(jìn)去的呢昂芜?我們先來(lái)看下\color{red}{doGetBean}:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {
......
    Object sharedInstance = getSingleton(beanName);
......
                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                                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);
                }
......

上述分析的getSingleton是第5行莹规,這里我們先關(guān)注第9行的getSingleton方法。單例模式下泌神,通過(guò)getSingleton(為和第5行的getSingleton區(qū)分良漱,我們稱(chēng)這個(gè)為第二個(gè)getSingleton)獲取bean,實(shí)現(xiàn)如下:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                ......
                    beforeSingletonCreation(beanName);
                ......
                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                ......
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
        }
                ......
    }

? 上面有singletonFactory.getObject()欢际,該方法的實(shí)現(xiàn)是在入?yún)⒅卸x的母市,即createBean(beanName, mbd, args)(后面詳細(xì)分析)。此外還有一個(gè)addSingleton的方法损趋,實(shí)現(xiàn)如下:

protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }

? 到這里患久,我們可以看到,一個(gè)全新的對(duì)象浑槽,是通過(guò)createBean創(chuàng)建完成蒋失,然后放到singletonObjects的。

? 接下來(lái)我們分析\color{red}{createBean}:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {
......
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
......

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            ......
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        ......
        return exposedObject;
    }

? 在創(chuàng)建bean的時(shí)候桐玻,先調(diào)用createBeanInstance生成一個(gè)BeanWrapper篙挽。他的最終調(diào)用只是newInstance了一個(gè)對(duì)象,沒(méi)有對(duì)對(duì)象進(jìn)行初始化镊靴,這就為后續(xù)的aop增強(qiáng)铣卡,以及循環(huán)對(duì)象的注入提供了條件观腊。

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
        try {
            ReflectionUtils.makeAccessible(ctor);
            return ctor.newInstance(args);
        }
        ......
    }

? 繼續(xù)回到doCreateBean方法,如下所示:

if (earlySingletonExposure) {
            ......
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

? 當(dāng)bean處于創(chuàng)建中算行,并且存在循環(huán)依賴(lài)時(shí)梧油,做了addSingletonFactory操作,如下所示:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }

? 這里我們可以看到州邢,singletonFactory被放到了singletonFactories儡陨,singletonFactory是new的那個(gè)ObjectFactory。這里ObjectFactory為什么要這么定義量淌,還有為什么需要使用singletonFactories骗村?二級(jí)緩存不能解決循環(huán)依賴(lài)問(wèn)題?這就需要關(guān)注getEarlyBeanReference呀枢。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    if (exposedObject == null) {
                        return null;
                    }
                }
            }
        }
        return exposedObject;
    }

? getEarlyBeanReference是由三級(jí)緩存singletonFactory中獲取對(duì)象的實(shí)現(xiàn)方法胚股,它調(diào)用的是org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference方法。實(shí)現(xiàn)如下:

public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            this.earlyProxyReferences.add(cacheKey);
        }
        return wrapIfNecessary(bean, beanName, cacheKey);
    }

繼續(xù)看下wrapIfNecessary裙秋,org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        ......

        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

? 上面通過(guò)createProxy方法琅拌,創(chuàng)建了帶有aop增強(qiáng)設(shè)置的方法。到此摘刑,第三級(jí)緩存singletonFactory的作用我們就清楚了进宝,主要是解決aop增強(qiáng)的實(shí)現(xiàn)。到這里我們可以得知new的ObjectFactory枷恕,最終幫助我們拿到了aop增強(qiáng)后的對(duì)象党晋。

? 接下來(lái)需要注意的方法是populateBean:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean:

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        PropertyValues pvs = mbd.getPropertyValues();
......
        if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }

        applyPropertyValues(beanName, mbd, bw, pvs);
    }

? populateBean用于填充對(duì)象的屬性。這里會(huì)填充對(duì)象依賴(lài)的其他對(duì)象信息徐块。上述代碼的postProcessPropertyValues方法未玻,最終會(huì)調(diào)用到:

org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates。

protected Map<String, Object> findAutowireCandidates(
            String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
......
        for (String candidateName : candidateNames) {
            if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
                result.put(candidateName, getBean(candidateName));
            }
        }
......
    }

? 上面的candidateName表示依賴(lài)的對(duì)象名稱(chēng)(B)胡控,這里可以看到扳剿,對(duì)于依賴(lài)的對(duì)象,又會(huì)重新調(diào)用getBean獲取bean對(duì)象铜犬。具體調(diào)用舞终,可以參考下面的調(diào)用堆棧圖:
循環(huán)依賴(lài)注入.png

\color{red}{小結(jié)}
? 我們清楚了三級(jí)緩存的作用,下面我們結(jié)合上述分析癣猾,看看三級(jí)緩存是如何解決循環(huán)依賴(lài)問(wèn)題的敛劝。

? 假設(shè)A依賴(lài)B,B依賴(lài)A纷宇。獲取A時(shí)夸盟,A和B在三級(jí)緩存都不存在,因此第一個(gè)getSingleton返回null像捶。之后會(huì)調(diào)doGetBean創(chuàng)建A上陕,創(chuàng)建A時(shí)桩砰,先調(diào)createBeanInstance得到一個(gè)newInstance的沒(méi)有實(shí)例化的對(duì)象。然后把對(duì)象A的工廠(chǎng)類(lèi)放到singletonFactories释簿,這里需要提的是亚隅,若A有做AOP增強(qiáng),那么放到singletonFactories的就是AOP增強(qiáng)后工廠(chǎng)類(lèi)庶溶。

? 接下來(lái)會(huì)在創(chuàng)建A中執(zhí)行populateBean方法煮纵,進(jìn)一步會(huì)調(diào)getBean,獲取B偏螺,這將重復(fù)上述過(guò)程行疏。

? 在獲取B時(shí),創(chuàng)建B的方法也會(huì)走到populateBean套像,這時(shí)酿联,B又會(huì)獲取A的對(duì)象。這時(shí)第二次獲取A對(duì)象的getBean方法夺巩,會(huì)在執(zhí)行第一個(gè)getSingleton時(shí)贞让,檢查到第三級(jí)緩存singletonFactories中有A的工廠(chǎng)方法,于是將對(duì)象A放到早期對(duì)象緩存earlySingletonObjects中劲够。這輪查詢(xún)震桶,有得到一個(gè)早期的對(duì)象A休傍,B將使用這個(gè)早期的對(duì)象A征绎,完成對(duì)象B的創(chuàng)建。

? B對(duì)象創(chuàng)建完成磨取,A對(duì)象還在earlySingletonObjects中人柿,在getSingleton中最后的addSingleton方法,會(huì)將對(duì)象A由二級(jí)緩存放到一級(jí)緩存singletonObjects中忙厌,這時(shí)獲取到完整的對(duì)象A凫岖。

二、構(gòu)造器中的循環(huán)依賴(lài)

? 接下來(lái)我們?cè)倏纯捶昃唬瑂pring能否處理構(gòu)造器中包含循環(huán)依賴(lài)的問(wèn)題哥放。

@Component
public class A {
    private B cb;

    @Autowired
    A(B b){
        this.cb = b;
    }
}
@Component
public class B {
    private A ca;

    @Autowired
    B(A a){
        this.ca = a;
    }
}

? 同樣,我們還是假設(shè)A的構(gòu)造器中依賴(lài)B爹土,B的構(gòu)造器中依賴(lài)A甥雕。我們回顧上述第二個(gè)getSingleton中的beforeSingletonCreation方法:

protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }

? 這里,singletonsCurrentlyInCreation保存的是當(dāng)前正在創(chuàng)建胀茵,但是還沒(méi)有創(chuàng)建完畢的類(lèi)社露,根據(jù)上述對(duì)循環(huán)依賴(lài)的分析,當(dāng)?shù)诙蝿?chuàng)建A時(shí)琼娘,singletonsCurrentlyInCreation中已經(jīng)包含A峭弟。這里附鸽,我們看下singletonsCurrentlyInCreation的定義:

private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));

? 這里,使用的是ConcurrentHashMap來(lái)保存瞒瘸,add方法實(shí)現(xiàn)為:

public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }

? 也就是說(shuō)坷备,當(dāng)map中已經(jīng)包含A時(shí),ConcurrentHashMap的put方法會(huì)返回舊值(非null)情臭,這里的add方法會(huì)返回false击你。通過(guò)調(diào)試,發(fā)現(xiàn)inCreationCheckExclusions也是空谎柄,因此丁侄,這時(shí)會(huì)拋BeanCurrentlyInCreationException異常,導(dǎo)致創(chuàng)建A失敗朝巫。因此鸿摇,spring無(wú)法直接解決構(gòu)造器中包含循環(huán)依賴(lài)的對(duì)象。

? 到這里劈猿,我們會(huì)問(wèn)到拙吉,spring為什么要這么設(shè)計(jì)呢?其實(shí)原因很簡(jiǎn)單揪荣,spring的早期對(duì)象A沒(méi)有被初始化筷黔,當(dāng)newInstatnce一個(gè)對(duì)象B時(shí),會(huì)執(zhí)行B的構(gòu)造方法仗颈,如果B的構(gòu)造方法中對(duì)早期對(duì)象A進(jìn)行操作佛舱,可能會(huì)拋異常。

? 那么挨决。Spring無(wú)法解決這個(gè)問(wèn)題嗎请祖?不是的,在構(gòu)造函數(shù)的循環(huán)依賴(lài)參數(shù)前使用@Lazy注解脖祈,即可在構(gòu)造器中使用循環(huán)依賴(lài)肆捕。

@Component
public class B {
    private A ca;

    @Autowired
    B(@Lazy A a){
        this.ca = a;
    }
}

三、總結(jié)

1.spring通過(guò)使用三級(jí)緩存來(lái)解決循環(huán)依賴(lài)的問(wèn)題盖高,之所以使用三級(jí)緩存而不是二級(jí)緩存慎陵,是因?yàn)檫€需要處理aop增強(qiáng)的類(lèi)。
2.spring無(wú)法直接解決構(gòu)造器循環(huán)依賴(lài)喻奥,但可以使用@Lazy注解實(shí)現(xiàn)構(gòu)造器的循環(huán)依賴(lài)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末席纽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子映凳,更是在濱河造成了極大的恐慌胆筒,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異仆救,居然都是意外死亡抒和,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)彤蔽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)摧莽,“玉大人,你說(shuō)我怎么就攤上這事顿痪∧髟” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵蚁袭,是天一觀(guān)的道長(zhǎng)征懈。 經(jīng)常有香客問(wèn)我,道長(zhǎng)揩悄,這世上最難降的妖魔是什么卖哎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮删性,結(jié)果婚禮上亏娜,老公的妹妹穿的比我還像新娘。我一直安慰自己蹬挺,他們只是感情好维贺,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著巴帮,像睡著了一般溯泣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晰韵,一...
    開(kāi)封第一講書(shū)人閱讀 52,184評(píng)論 1 308
  • 那天发乔,我揣著相機(jī)與錄音,去河邊找鬼雪猪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛起愈,可吹牛的內(nèi)容都是我干的只恨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼抬虽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼官觅!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起阐污,我...
    開(kāi)封第一講書(shū)人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤休涤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體功氨,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡序苏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捷凄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忱详。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖跺涤,靈堂內(nèi)的尸體忽然破棺而出匈睁,到底是詐尸還是另有隱情,我是刑警寧澤桶错,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布航唆,位于F島的核電站,受9級(jí)特大地震影響院刁,放射性物質(zhì)發(fā)生泄漏佛点。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一黎比、第九天 我趴在偏房一處隱蔽的房頂上張望超营。 院中可真熱鬧,春花似錦阅虫、人聲如沸演闭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)米碰。三九已至,卻和暖如春购城,著一層夾襖步出監(jiān)牢的瞬間吕座,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工瘪板, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吴趴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓侮攀,卻偏偏與公主長(zhǎng)得像锣枝,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子兰英,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359