spring-BeanFactory學(xué)習(xí)(一)

上周主要了解了spring boot項目啟動過程中希坚,beanFactory的繼承體系,以及beanFactory是怎么創(chuàng)建的玛痊。今天繼續(xù)來看下beanFactory這個容器的詳細(xì)信息锌俱,因為beanFactory屬性和方法比較多迎膜,今天主要看下它比較重要的幾個屬性和方法负蚊。

一神妹、屬性

beanFactory負(fù)責(zé)管理bean的加載,實例化家妆,維護bean之間的依賴關(guān)系鸵荠,負(fù)責(zé)bean的聲明周期,再加上DefaultListableBeanFactory的父類也比較多伤极,也導(dǎo)致了beanFactory屬性非常的多蛹找。下面是我認(rèn)為比較重要的一些屬性,這些屬性可能是定義在DefaultListableBeanFactory類中塑荒,也可能定義在其父類中熄赡,但是為了方便我就全部寫到一起了姜挺,下面是代碼:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    // 繼承子父類的屬性
    // 創(chuàng)建bean實例的策略齿税,使用的是cglib
    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
    // 是否自動嘗試解析bean之間的循環(huán)引用
    private boolean allowCircularReferences;
    // 在依賴性檢查和自動裝配時忽略的依賴關(guān)系類型,存儲的為Class對象
    private final Set<Class<?>> ignoredDependencyTypes;
    // 在依賴性檢查和自動裝配時忽略的依賴關(guān)系類型炊豪,存儲的為Class對象凌箕。默認(rèn)值忽略BeanFactory
    private final Set<Class<?>> ignoredDependencyInterfaces;
    // 當(dāng)前正在創(chuàng)建的bean的名稱,用于從用戶指定的Supplier回調(diào)觸發(fā)的getBean等調(diào)用的隱式依賴注冊词渤。
    private final NamedThreadLocal<String> currentlyCreatedBean;
    // 是否緩存bean的元數(shù)據(jù)牵舱,或者每次訪問時重新獲取
    private boolean cacheBeanMetadata = true;
    // 要在createBean中應(yīng)用的BeanPostProcessors
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList();
    // 從bean名稱映射到合并的RootBeanDefinition
    private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap(256);
    // 已經(jīng)創(chuàng)建至少一次的bean的名稱
    private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap(256));
    // 當(dāng)前正在創(chuàng)建的bean的名稱
    private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal("Prototype beans currently in creation");    

    // 本身的屬性值//
    // 是否允許使用相同bean名稱重新注冊不同的bean定義,即注冊的兩個相同的名字的bean缺虐,且用后面的bean覆蓋前面的
    private boolean allowBeanDefinitionOverriding = true;
    // 是否允許預(yù)加載
    private boolean allowEagerClassLoading = true;
    // 檢查bean定義是否為一個autowire注入的解析器
    private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
    // 根據(jù)依賴類型映射到相應(yīng)的自動注入的值map集合
    private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap(16);
    // 鍵值是bean名稱芜壁,映射值為bean定義對象的map集合
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
    // 以依賴類型的類對象為鍵,所有bean(單例非單例)的名稱為值得map集合
    private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap(64);
    // 以依賴類型的類對象為鍵高氮,所有單例bean的名稱為值的map集合
    private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap(64);
    // bean定義的名稱list慧妄,按照注冊順序
    private volatile List<String> beanDefinitionNames = new ArrayList(256);
   
    // 省略
    ....
}

看到這里我就記得上次中遇到的一個問題,就是同名bean的創(chuàng)建剪芍,當(dāng)時日志顯示的當(dāng)前bean的類型不是期望的類型塞淹,因為allowBeanDefinitionOverriding的屬性值默認(rèn)為true。當(dāng)然這個屬性是可以修改的罪裹,有興趣可以網(wǎng)上找一下相關(guān)方法饱普。有些屬性又會涉及到很多不太熟悉的類,比如AutowireCandidateResolver状共、BeanDefinition套耕、RootBeanDefinition等等,AutowireCandidateResolver是檢查bean是否通過Autowire注入的解析器峡继。BeanDefinition描述了一個bean實例箍铲,它保存相關(guān)的屬性值,構(gòu)造函數(shù)參數(shù)值以及具體實現(xiàn)提供的更多信息鬓椭。RootBeanDefinition表示合并的bean定義颠猴,它在運行時支持BeanFactory中的特定bean关划,它本質(zhì)上是運行時的“統(tǒng)一”bean定義視圖。反正遇到不清楚的就去看下源碼的注解翘瓮,有時不一定非要特別清楚贮折,了解它的作用就行。接下來我們看下相關(guān)的一些方法吧资盅,同樣的调榄,這些方法可能是DefaultListableBeanFactory類,也可能是其父類的呵扛。

二每庆、相關(guān)方法

方法也非常多,一樣選擇幾個來看今穿。beanFactory負(fù)責(zé)bean的加載缤灵、實例化以及相互之間的關(guān)系,我們對應(yīng)一個一個蓝晒。

1腮出、創(chuàng)建bean

創(chuàng)建bean的方法來自于AbstractAutowireCapableBeanFactory,下面我們看看源碼芝薇,簡單的分析一下大概的過程胚嘲。

public <T> T createBean(Class<T> beanClass) throws BeansException {
    RootBeanDefinition bd = new RootBeanDefinition(beanClass);
    bd.setScope(SCOPE_PROTOTYPE);
    bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
    return (T) createBean(beanClass.getName(), bd, null);
}

首先以類對象為參數(shù)創(chuàng)建出RootBeanDefinition實例,然后設(shè)置其為原型模式洛二,即prototype馋劈,這樣的目的就是為了避免它作為一個依賴bean存在,因為每個RootBeanDefinition創(chuàng)建都需要一個對應(yīng)的bean的類對象晾嘶。然后調(diào)用下面的方法

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isDebugEnabled()) {
                logger.debug("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }

這個方法里面先執(zhí)行resolveBeanClass(mbd, beanName)方法妓雾,即根據(jù)RootBeanDefinition實例和bean名稱為參數(shù),去解析對應(yīng)的類對象变擒,返回結(jié)果為bean名稱的類對象君珠。這個過程中會將已解析的Class存儲在bean定義中以供進(jìn)一步使用。然后執(zhí)行prepareMethodOverrides方法娇斑,該方法主要為了驗證并準(zhǔn)備為此bean定義的方法覆蓋策添,檢查其是否存在具有指定名稱的方法。然后是resolveBeforeInstantiation方法毫缆,即在實例化之前解析唯竹,這個方法為BeanPostProcessors提供返回代理對象而不是目標(biāo)bean實例的機會,也就是說如果在實例化之間檢驗是否有這個bean的一個代理對象苦丁,有的話直接返回該代理對象浸颓,否則繼續(xù)執(zhí)行下面doCreateBean方法,我們看下doCreateBean源碼

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

1、這個方法先判斷RootBeanDefinition是否為單例产上,如果為單例則從factoryBeanInstanceCache中移除該bean名稱棵磷,否則執(zhí)行2。
2晋涣、執(zhí)行createBeanInstance方法創(chuàng)建bean實例仪媒,這個方法會使用適當(dāng)?shù)膶嵗呗詾橹付ǖ腷ean創(chuàng)建新實例:比如工廠方法,構(gòu)造函數(shù)自動裝配或簡單實例化谢鹊,返回結(jié)果是一個bean的包裝類對象算吩。getWrappedInstance和getWrappedClass方法反別返回相應(yīng)的bean對象和bean的類對象,并將該類對象賦值給resolvedTargetType佃扼。
3偎巢、接下來的同步代碼塊主要是為了允許post-processors(后處理器)修改合并的bean定義,即將MergedBeanDefinitionPostProcessors應(yīng)用于指定的bean定義兼耀,并調(diào)用其postProcessMergedBeanDefinition方法压昼。關(guān)于這點我也還不是太理解具體的作用。
4翠订、判斷是否支持earlySingletonExposure巢音,即熱緩存單例遵倦,以保證即使在BeanFactoryAware等生命周期接口觸發(fā)時也能夠解析循環(huán)引用尽超。如果是則將創(chuàng)建新的單例工廠以構(gòu)建指定的單例bean。
5梧躺、初始化bean實例似谁,先執(zhí)行populateBean方法,即使用bean定義中的屬性值填充給定bean的包裝類對象中的bean實例掠哥。然后執(zhí)行initializeBean方法巩踏,初始化給定的bean實例,應(yīng)用工廠回調(diào)以及init方法和bean后處理器续搀。
6塞琼、判斷earlySingletonExposure屬性值,如果為true禁舷,則獲取早期的單例bean引用彪杉,如果不為空進(jìn)行后續(xù)判斷判斷初始化后的exposedObject和第2步中的bean是否同一個bean,是將將早期單列bean引用賦值給exposedObject牵咙,否則繼續(xù)進(jìn)行其他判斷派近。
7、執(zhí)行registerDisposableBeanIfNecessary方法洁桌,將bean注冊為一次性bean渴丸。最后返回相應(yīng)bean實例。
當(dāng)然我說是比較簡單的,其實中間過程非常的復(fù)雜谱轨,因為涉及的方法很多戒幔,自己沒辦法每一個都貼一段代碼,所以只能將就看吧土童。
2溪食、初始化bean
初始化給定的bean實例,應(yīng)用工廠回調(diào)以及init方法和bean后處理器娜扇。這個在上面的createBean方法中有調(diào)用過错沃,我們看下具體的代碼

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

1、判斷系統(tǒng)的securityManager是否為null雀瓢,不為null執(zhí)行AccessController.doPrivileged方法枢析;否則執(zhí)行2。
2刃麸、執(zhí)行invokeAwareMethods方法醒叁,該方法兩個參數(shù),分別為bean名稱beanName和實例bean泊业。判斷給定的bean是否為BeanNameAware實例把沼,是則將bean實例名稱設(shè)置為beanName;判斷給定的bean是否為BeanClassLoaderAware實例吁伺,然后獲取ClassLoader饮睬,不為空是則將ClassLoader引用賦值給bean的beanClassLoader變量;最后判斷bean實例是否為BeanFactoryAware篮奄,是則調(diào)用setBeanFactory方法捆愁,將AbstractAutowireCapableBeanFactory實例賦值給bean的beanFactory變量。
3窟却、將bean實例賦值給變量wrappedBean昼丑,然后判斷RootBeanDefinition即mbd是否為null或者mbd為非合成,執(zhí)行applyBeanPostProcessorsBeforeInitialization方法夸赫,該方法會獲取到BeanPostProcessor實例菩帝,并執(zhí)行各自的postProcessBeforeInitialization實現(xiàn),其返回的bean實例可能是是原始實例的包裝器對象茬腿。
4呼奢、執(zhí)行invokeInitMethods方法,這個方法會將bean所有屬性值都被設(shè)置滓彰,并了解它屬于的bean工廠控妻。這個需要檢查該bean是否實現(xiàn)了InitializingBean或定義了一個自定義init方法,并調(diào)用必要的回調(diào)方法揭绑」颍看下面的代碼:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

先判斷bean是否實現(xiàn)了InitializingBean郎哭,如果是,且滿足其他判斷條件菇存,則執(zhí)行afterPropertiesSet方法夸研。如果mbd不為null,且bean實例的類對象不為NullBean依鸥,則從RootBeanDefinition實例獲取initMethodName名稱亥至,如果滿足判斷條件,則執(zhí)行invokeCustomInitMethod方法贱迟,該方法通過反射執(zhí)行自定義的init方法姐扮。
5、執(zhí)行mbd為null或者mbd.isSynthetic()為false的判斷條件衣吠,滿足條件執(zhí)行applyBeanPostProcessorsAfterInitialization茶敏,即完成初始化后應(yīng)用BeanPostProcessors方法,該方法和3中的applyBeanPostProcessorsBeforeInitialization方法比較相像缚俏,都是執(zhí)行每個PostProcessor各自的postProcessAfterInitialization方法惊搏。最后返回wrappedBean,這個是一個原始bean的包裝器對象忧换。


其實初始化bean的方法應(yīng)該算是創(chuàng)建bean的一個部分恬惯,我為了區(qū)分就單獨拿出來了,今天主要就是了解beanFactory的成員變量以及兩個方法亚茬,但是這兩個方法比我想象的還是要復(fù)雜一點酪耳,代碼還是蠻多的,關(guān)于其他的一些方法我們下次繼續(xù)再看才写。
最后想說一下周五的一個面試情況葡兑,自己雖然投了十幾份簡歷也就那么2奖蔓、3家面試邀請赞草,但是因為在異地,自己拒了一家吆鹤。星期五我覺得很有必要去面一下厨疙,請假去了上海。周五面的是中通快遞疑务,地點很偏僻沾凄,面試體驗也并不太好,當(dāng)然自己也沒有怎么準(zhǔn)備(有點托大知允,后悔)撒蟀。面試問題主要是Java基礎(chǔ),多線程我說沒怎么用過面試官就沒問了温鸽,其實這部分自己看得東西也蠻多的保屯;然后spring cloud和dubbo對比手负,這個我沒回答好,缺少實際的使用經(jīng)驗姑尺。mybatis的一點基礎(chǔ)OGNL表達(dá)式和EL表達(dá)式的區(qū)別竟终,我只記得OGNL能更好的防止SQL注入;redis持久化的兩種方式切蟋,自認(rèn)為答的還行统捶,畢竟前段時間剛學(xué)了;然后就是Java基礎(chǔ)柄粹,問的也不多喘鸟,都是比較常規(guī)的,自己覺得回答都還OK驻右。另外數(shù)據(jù)庫索引方面的知識迷守,面試官問索引最優(yōu)實現(xiàn)以及給了一個場景自己判斷需不需要加索引,怎么加索引旺入,雖然自己學(xué)了兑凿,但是感覺回答的不是很好。面試時間挺短的茵瘾,自己還等了HR半個小時礼华,后來HR說初始先這樣吧,我覺得應(yīng)該是沒戲了,畢竟HR都沒面颂跨。感覺自己還是需要多出去面試一下戚揭,刷下經(jīng)驗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扮匠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子凡涩,更是在濱河造成了極大的恐慌棒搜,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件活箕,死亡現(xiàn)場離奇詭異力麸,居然都是意外死亡,警方通過查閱死者的電腦和手機育韩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門克蚂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人筋讨,你說我怎么就攤上這事埃叭。” “怎么了悉罕?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵赤屋,是天一觀的道長误墓。 經(jīng)常有香客問我,道長益缎,這世上最難降的妖魔是什么谜慌? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮莺奔,結(jié)果婚禮上欣范,老公的妹妹穿的比我還像新娘。我一直安慰自己令哟,他們只是感情好恼琼,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屏富,像睡著了一般晴竞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狠半,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天噩死,我揣著相機與錄音,去河邊找鬼神年。 笑死已维,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的已日。 我是一名探鬼主播垛耳,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼飘千!你這毒婦竟也來了堂鲜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤护奈,失蹤者是張志新(化名)和其女友劉穎缔莲,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逆济,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡酌予,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了奖慌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡松靡,死狀恐怖简僧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情雕欺,我是刑警寧澤岛马,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布棉姐,位于F島的核電站,受9級特大地震影響啦逆,放射性物質(zhì)發(fā)生泄漏伞矩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一夏志、第九天 我趴在偏房一處隱蔽的房頂上張望乃坤。 院中可真熱鬧,春花似錦沟蔑、人聲如沸湿诊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽厅须。三九已至,卻和暖如春食棕,著一層夾襖步出監(jiān)牢的瞬間朗和,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工簿晓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留例隆,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓抢蚀,卻偏偏與公主長得像镀层,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子皿曲,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

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

  • Spring入門使用Spring容器Spring容器使用ApplicationContextApplication...
    漸丶忘閱讀 1,409評論 0 4
  • 最近想系統(tǒng)的學(xué)習(xí)一下Spring的相關(guān)知識唱逢,在這里分享一下。也希望能幫助那些對英文技術(shù)文檔閱讀比較困難的朋友屋休。接下...
    Aiibai閱讀 1,559評論 5 16
  • 本來是準(zhǔn)備看一看Spring源碼的坞古。然后在知乎上看到來一個帖子,說有一群**自己連Spring官方文檔都沒有完全讀...
    此魚不得水閱讀 6,935評論 4 21
  • IOC和DI是什么劫樟? Spring IOC 的理解痪枫,其初始化過程? BeanFactory 和 FactoryBe...
    justlpf閱讀 3,475評論 1 21
  • 生物多樣性的一個表現(xiàn)是叠艳,為了滿足某種功用奶陈,比如具備視覺,不同種動物在進(jìn)化這個大導(dǎo)演的指揮附较,可謂精彩紛呈形式不一吃粒。這...
    我愛雨果閱讀 4,161評論 3 20