SpringIoC-容器初始化過(guò)程

IoC:依賴倒置原理,個(gè)人覺(jué)得其核心思想就是減少代碼的耦合度,很多復(fù)雜的應(yīng)用都是依靠多個(gè)類之間的合作來(lái)完成的迅细。如果類本身和合作類的引用需要靠自身來(lái)實(shí)現(xiàn),那么代碼的耦合度會(huì)很高淘邻。那么在Spring中茵典,IoC是實(shí)現(xiàn)依賴反轉(zhuǎn)的載體;Spring在對(duì)象初始化的時(shí)候?qū)?shù)據(jù)注入到對(duì)象中,或者將對(duì)象的引用注入到數(shù)據(jù)域中的方式來(lái)注入對(duì)方法調(diào)用的依賴

Spring IoC提供了一個(gè)基本的javaBean容器宾舅,通過(guò)IoC模式管理依賴關(guān)系,并通過(guò)依賴注入和AOP切面增強(qiáng)了為javeBean這樣的POJO對(duì)象賦予事務(wù)管理统阿,生命周期管理等基本功能彩倚。而Bean都在Spring容器里,Spring容器負(fù)責(zé)它們的創(chuàng)建扶平,裝配帆离,管理它們整個(gè)的生命周期结澄「绻龋《深入理解Spring技術(shù)內(nèi)幕》

SpringIoC容器系列(BeanFactory跟ApplicationContext)

BeanFactory跟ApplicationContext都屬于Spring容器们妥。
BeanFactory:定義了最基本的容器設(shè)計(jì)規(guī)范,如getBean(),containBean(),getType()等基本的方法勉吻。

ApplicationContext:由圖可知ApplicationContext應(yīng)用的上下文都是基于ConfigurableApplicationContext跟WebApplicationContext的實(shí)現(xiàn)监婶。ApplicationContext繼承了BeanFactory的接口同時(shí)又繼承MessageSource(支持不同的信息源),ResourceLoader(訪問(wèn)資源),ApplicationEventPublisher(支持應(yīng)用事件)。

IoC接口設(shè)計(jì)圖

圖片引用《深入理解spring技術(shù)內(nèi)幕》

容器是如何初始化的齿桃?

容器的初始化是通過(guò)refresh()方法來(lái)完成的惑惶,總共包括三個(gè)步驟:

  • 定位:通過(guò)Resource定位BeanDefinition,BeanDefinition抽象了對(duì)bean的定義源譬,比如bean的信息集惋,依賴關(guān)系等。這個(gè)過(guò)程可以想象成尋找bean的過(guò)程踩娘。

下面我們通過(guò)代碼來(lái)簡(jiǎn)要分析下容器是如何初始化的

public class ApplicationContextInit {

    public static void main(String[] args) {
        FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("bean.xml");
    }
}

FileSystemXmlApplicationContext是通過(guò)文件來(lái)載入Resource的,運(yùn)行上述代碼

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
    //...省略部分源碼
    //通過(guò)文件的位置來(lái)定位到beanDefinition
    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }
    
    //通過(guò)refresh()方法來(lái)完成BeanDefinition信息讀取和載入
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
    @Override
    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }

}

refresh()來(lái)啟動(dòng)IoC容器的初始化

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 容器初始化的一些準(zhǔn)備工作.
            prepareRefresh();

            // 告知子類要初始化BeanFactory刮刑,BeanDefinition信息的讀取是在子類的
            // refreshBeanFactory()方法里完成的
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 準(zhǔn)備bean工廠以在此上下文中使用。
            prepareBeanFactory(beanFactory);

            try {
                // 設(shè)置beanFactory的后置處理
                postProcessBeanFactory(beanFactory);
                // 調(diào)用beanFactory的后置處理
                invokeBeanFactoryPostProcessors(beanFactory);
                // 注冊(cè)beanFactory的后置處理
                registerBeanPostProcessors(beanFactory);
                // 初始化上下文的消息
                initMessageSource();
                // 初始化上下的事件
                initApplicationEventMulticaster();
                // 初始化一些特殊的bean
                onRefresh();
                // 檢查一些監(jiān)聽(tīng)的bean并注冊(cè)到容器中
                registerListeners();
                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
                // 發(fā)布容器事件养渴,結(jié)束Refresh過(guò)程
                finishRefresh();
            }
            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // 銷毀已經(jīng)生成的bean
                destroyBeans();
                // 重置激活狀態(tài).
                cancelRefresh(ex);
                throw ex;
            }

            finally {
            
                resetCommonCaches();
            }
        }
    }

beanDefinition信息是通過(guò)ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()里的refreshBeanFactory()來(lái)完成的雷绢,而這個(gè)方法則是在AbstractRefreshableApplicationContext實(shí)現(xiàn)的。

@Override
    protected final void refreshBeanFactory() throws BeansException {
            //如果容器已經(jīng)存在,那么銷毀并且關(guān)閉該容器,保證每次產(chǎn)生的都是新的容器
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
                   //創(chuàng)建基礎(chǔ)的BeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
                   //載入BeanDefinition的信息
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

DefaultListableBeanFactory其實(shí)是一個(gè)最基礎(chǔ)的容器,很多容器都是基于這個(gè)容器來(lái)作擴(kuò)展,那么這個(gè)容器里自然也包含了很多基礎(chǔ)重要的功能理卑,那么通過(guò)loadBeanDefinitions()來(lái)完成BeanDefinition信息的載入的,這里是委托子類來(lái)完成這個(gè)工作的翘紊。

//抽象類,具體的resource定位跟BeanDefinition的載入是委托子類來(lái)完成的
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
            throws BeansException, IOException;


//這是loadBeanDefinitions的具體實(shí)現(xiàn)
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//創(chuàng)建XmlBeanDefinitionReader,并通過(guò)回調(diào)設(shè)置到beanFactory里面去
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// 使用此上下文的資源加載環(huán)境配置beanFactory
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//啟動(dòng)bean信息的載入過(guò)程
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }
//這里應(yīng)該算是容器初始化第一步resource定位,首先得到beanDefinition信息的Resource定位
//然后通過(guò)XmlBeanDefinitionReader來(lái)讀取
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//通過(guò)resource來(lái)定位
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
//通過(guò)文件路徑來(lái)定位
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }


public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//獲取ResourceLoader
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }
              //判斷ResourceLoader的路徑模式,
        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int loadCount = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    for (Resource resource : resources) {
                        actualResources.add(resource);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }
                return loadCount;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        else {
            // Can only load single resources by absolute URL.
            Resource resource = resourceLoader.getResource(location);
            int loadCount = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }
            return loadCount;
        }
    }

getResourceByPath被子類FileSystemXmlApplicationContext實(shí)現(xiàn),最終返回FileSystemResource對(duì)象藐唠,通過(guò)這個(gè)對(duì)象,Spring進(jìn)行相關(guān)的I/O操作帆疟,完成beanDefinition的定位。
總結(jié)下Resource定位BeanDefinition的流程
1.FileSystemXmlApplicationContext里調(diào)用refresh()方法初始化IoC容器宇立。
2.在refresh()方法里調(diào)用obtainFreshBeanFactory()里面的refreshBeanFactory()來(lái)完成BeanDefinition的定位,而refreshBeanFactory()是由子類AbstractRefreshableApplicationContext來(lái)實(shí)現(xiàn)的踪宠。
3.refreshBeanFactory()中是通過(guò)loadBeanDefinitions()來(lái)完成BeanDefinition的定位,而loadBeanDefinitions()是一個(gè)抽象的方法,具體由AbstractBeanDefinitionReader里的loadBeanDefinitions()來(lái)實(shí)現(xiàn)。
4.在loadBeanDefinitions()通過(guò)DefaultResourceLoader的getResource方法里返回resource對(duì)象妈嘹。

  • 載入:BeanDefinition的信息已經(jīng)定位到了柳琢,第二步就是把定義的BeanDefinition在Ioc容器中轉(zhuǎn)化成一個(gè)Spring內(nèi)部標(biāo)示的數(shù)據(jù)結(jié)構(gòu)的過(guò)程。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (this.logger.isInfoEnabled()) {
            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }

        if (!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
                  //準(zhǔn)備讀取xml文件
                InputStream inputStream = encodedResource.getResource().getInputStream();

                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                  //具體的讀取過(guò)程是在doLoadBeanDefinitions()這個(gè)方法里完成
                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                    inputStream.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if (((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var5;
        }
    }
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            int validationMode = getValidationModeForResource(resource);
              //這里通過(guò)documentLoader來(lái)讀取xml最終獲取Document對(duì)象
            Document doc = this.documentLoader.loadDocument(
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
             //這里通過(guò)registerBeanDefinitions()方法完成BeanDefinition的解析
            return registerBeanDefinitions(doc, resource);
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
          //獲取BeanDefinitionDocumentReader對(duì)xml對(duì)BeanDefinition進(jìn)行解析
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        documentReader.setEnvironment(this.getEnvironment());
        int countBefore = getRegistry().getBeanDefinitionCount();
       //具體解析是在registerBeanDefinitions()這個(gè)方法里進(jìn)行對(duì)
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
             //注冊(cè)BeanDefinition
        doRegisterBeanDefinitions(root);
    }

protected void doRegisterBeanDefinitions(Element root) {
        //委托父類解析
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }

        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);

        this.delegate = parent;
    }

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //對(duì)xml里根節(jié)點(diǎn)下所有對(duì)子節(jié)點(diǎn)進(jìn)行解析
        if (delegate.isDefaultNamespace(root)) {
            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;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }


    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            //如果為bean的話 解析BeanDefinition
            processBeanDefinition(ele, delegate);
        }//beans
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // 遞歸解析
            doRegisterBeanDefinitions(ele);
        }
    }
 
    
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
 
}

首先通過(guò)調(diào)用XML的解析器得到Document對(duì)象,此時(shí)這些Document對(duì)象并沒(méi)有按照Spring的Bean規(guī)則進(jìn)行解析柬脸,在完成通用的XML解析以后他去,才是按照Spring Bean規(guī)則進(jìn)行解析的地方,這個(gè)過(guò)程在documentReader中實(shí)現(xiàn)倒堕,使用的documentReader是默認(rèn)設(shè)置好的DefaultBeanDefinitionDocumentReader灾测。

  • 注冊(cè):將抽象好的BeanDefinition統(tǒng)一注冊(cè)到IoC容器中,IoC容器是通過(guò)hashMap來(lái)維護(hù)BeanDefinition信息的涩馆,key為beanName行施,value為BeanDefinition。
/** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

BeanDefinition的注冊(cè)是發(fā)生在BeanDefinition信息載入之后的魂那,

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition oldBeanDefinition;
              //如果beanName已經(jīng)在map里存在,那么拋出異常
        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        if (oldBeanDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
            }
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
                  
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {

           // 使用synchronize為了保證數(shù)據(jù)一致性蛾号,key為bean的名字,key為beanDefinition信息
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

這樣就完成了beanDefinition在IoC容器中的注冊(cè);
下一篇會(huì)大概分析下依賴注入的過(guò)程, 第一次寫這種源碼分析的文章,思路還是比較混亂,還請(qǐng)大家多多指教,共同進(jìn)步!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涯雅,一起剝皮案震驚了整個(gè)濱河市鲜结,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌活逆,老刑警劉巖精刷,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蔗候,居然都是意外死亡怒允,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門锈遥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)纫事,“玉大人,你說(shuō)我怎么就攤上這事所灸±龌蹋” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵爬立,是天一觀的道長(zhǎng)钾唬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)侠驯,這世上最難降的妖魔是什么抡秆? 我笑而不...
    開(kāi)封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮吟策,結(jié)果婚禮上琅轧,老公的妹妹穿的比我還像新娘。我一直安慰自己踊挠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著效床,像睡著了一般睹酌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剩檀,一...
    開(kāi)封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天憋沿,我揣著相機(jī)與錄音,去河邊找鬼沪猴。 笑死辐啄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的运嗜。 我是一名探鬼主播壶辜,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼担租!你這毒婦竟也來(lái)了砸民?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤奋救,失蹤者是張志新(化名)和其女友劉穎岭参,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尝艘,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡演侯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了背亥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秒际。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖隘梨,靈堂內(nèi)的尸體忽然破棺而出程癌,到底是詐尸還是另有隱情,我是刑警寧澤轴猎,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布嵌莉,位于F島的核電站,受9級(jí)特大地震影響捻脖,放射性物質(zhì)發(fā)生泄漏锐峭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一可婶、第九天 我趴在偏房一處隱蔽的房頂上張望沿癞。 院中可真熱鬧,春花似錦矛渴、人聲如沸椎扬。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蚕涤。三九已至筐赔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間揖铜,已是汗流浹背茴丰。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留天吓,地道東北人贿肩。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像龄寞,于是被迫代替她去往敵國(guó)和親汰规。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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

  • 不知從哪一年開(kāi)始萄焦,時(shí)興起了過(guò)母親節(jié)控轿。今天是2018年5月份的第二個(gè)周日,朋友圈全都是祝福母親節(jié)的文字拂封,有祝福祝愿的...
    龍寶青青閱讀 514評(píng)論 2 1
  • 一個(gè)新年冒签,一個(gè)寒假在抛,轉(zhuǎn)瞬即逝进栽,都沒(méi)感覺(jué)能好好休息就過(guò)去了纽窟! 整個(gè)假期桥嗤,女兒除了做作業(yè)還是做作業(yè)蔚携,唯一看過(guò)的電視節(jié)目...
    妖精夏顏閱讀 302評(píng)論 1 4
  • 阮咸,西晉時(shí)期陳留尉氏人(今河南開(kāi)封尉氏縣)缕探,字仲容似踱。阮咸是阮籍之侄捍靠,建安七子之一的阮瑀之孫走趋。與阮籍并稱為“大小阮...
    KobbBryant閱讀 835評(píng)論 0 1
  • 每天午飯前一段時(shí)間,是小朋友最吵鬧的一個(gè)時(shí)期.由于這時(shí)有部分家長(zhǎng)來(lái)接幼兒回家吃午飯,因此又不能組織正常的教學(xué)活動(dòng)衅金,...
    丶高倩閱讀 439評(píng)論 0 2