Spring源碼(四)-bean的加載(上)

前言

前面講述了context的創(chuàng)建,接下來將進入到核心的bean的創(chuàng)建過程,前期的準(zhǔn)備工作已經(jīng)完成,相信很多人跟我一樣,看過了一遍只能有個大概的印象,接下來有時間的話我會考慮結(jié)合UML和腦圖這樣的出來和大家一起分享,有經(jīng)驗或者想一起學(xué)習(xí)的,希望可以聯(lián)系我,qq:616516146,言歸正傳,回到代碼。

1、prepareContext()

接下來回到最初代碼SpringApplication中run方法,我們先看prepareContext()這個方法。該方法是做context的準(zhǔn)備工作。我們進入代碼中看下他的具體實現(xiàn)。

    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        /**
         * 該方法對context進行了預(yù)設(shè)置,設(shè)置了ResourceLoader和ClassLoader,
         * 并向bean工廠中添加了一個beanNameGenerator
         */

        postProcessApplicationContext(context);
        /**
         *
         * applyInitializers(context)方法
         * 獲取到了我們或spring通過SpringApplication.setInitializers(xxx)
         * 設(shè)置的應(yīng)用上下文初始化器集合
         */
        applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

        // Add boot specific singleton beans
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // Load the sources
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        /**
         * 將各種bean裝載進context對象中
         */
        load(context, sources.toArray(new Object[sources.size()]));
        listeners.contextLoaded(context);
    }


我們主要只討論 postProcessApplicationContext(context)、 applyInitializers(context)以及 load(context, sources.toArray(new Object[sources.size()]))這三個方法

  • 1、postProcessApplicationContext(context)
    該方法對context進行了預(yù)設(shè)置,設(shè)置了ResourceLoader和ClassLoader, 并向bean工廠中添加了一個beanNameGenerator
  • 2、applyInitializers(context)
    該方法獲取到了我們或spring通過SpringApplication.setInitializers(xxx)設(shè)置的應(yīng)用上下文初始化器集合。
  • 3、load(context, sources.toArray(new Object[sources.size()]))
    這個方法主要是加載各種beans到context對象中的。sources代表各種資源對象,然后BeanDefinitionLoader的內(nèi)部通過各種xxxReader和xxxScanner讀取、解析這些資源對象中的beans
    /**
     * Load beans into the application context.
     * @param context the context to load beans into
     * @param sources the sources to load
     * 這個方法主要是加載各種beans到context對象中的。
     * sources代表各種資源對象,然后BeanDefinitionLoader
     * 的內(nèi)部通過各種xxxReader和xxxScanner讀取、解析這些資源對象中的beans。
     * 具體細節(jié)在    BeanDefinitionLoader中實現(xiàn)
     */
    protected void load(ApplicationContext context, Object[] sources) {
        logger.debug("開始執(zhí)行l(wèi)oad方法");
        System.out.println("-------------開始執(zhí)行l(wèi)oad方法");
        if (logger.isDebugEnabled()) {
            logger.debug(
                    "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
        BeanDefinitionLoader loader = createBeanDefinitionLoader(
                getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        loader.load();
    }

以上是load方法加載。
上面三個方法完成之后,prepareContext()函數(shù)已經(jīng)準(zhǔn)備好了refresh上下文的基礎(chǔ)準(zhǔn)備工作。,接下來看refresh的相關(guān)工作。

2、refresh

private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
    if (this.registerShutdownHook) {
        try {
            /**
             * 又注冊了關(guān)閉context時的鉤子
             */
            context.registerShutdownHook();
        }
        catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}

這里我們進入refresh看看里面的具體實現(xiàn),此處的refrsh調(diào)用的是AbstractApplicationContext的refrsh方法,之后又調(diào)用了context.registerShutdownHook();關(guān)閉了鉤子。進入到AbstractApplicationContext,看下refrsh的具體實現(xiàn),這里只截取了一部分代碼

synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    prepareRefresh();
    // Tell the subclass to refresh the internal bean factory.
    //BeanFactory創(chuàng)建
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);
    try {
        // Allows post-processing of the bean factory in context subclasses.
        postProcessBeanFactory(beanFactory);
        // Invoke(調(diào)用) factory processors registered as beans in the context.
        //DefaultListableBeanFactory,完成basepackage的掃描
        invokeBeanFactoryPostProcessors(beanFactory);
        // Register bean processors that intercept bean creation.
        registerBeanPostProcessors(beanFactory);
        // Initialize message source for this context.
        initMessageSource();
        // Initialize event multicaster for this context.
        initApplicationEventMulticaster();
        // Initialize other special beans in specific context subclasses.
        onRefresh();
        // Check for listener beans and register them.
        registerListeners();
        // Instantiate all remaining (non-lazy-init) singletons.
        //DefaultListableBeanFactory
        //該方法進行了非懶加載beans的初始化工作
        finishBeanFactoryInitialization(beanFactory);
        // Last step: publish corresponding event.
        finishRefresh();
    }

這里我們只重點關(guān)注 finishBeanFactoryInitialization(beanFactory)這個方法。

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // Initialize conversion service for this context.
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
            beanFactory.setConversionService(
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
        }

        // Register a default embedded value resolver if no bean post-processor
        // (such as a PropertyPlaceholderConfigurer bean) registered any before:
        // at this point, primarily for resolution in annotation attribute values.
        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
        }

        // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        for (String weaverAwareName : weaverAwareNames) {
            logger.info("----------weaverAwareName:"+weaverAwareName);
            //創(chuàng)建bean的實例
            getBean(weaverAwareName);
        }

        // Stop using the temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(null);

        // Allow for caching all bean definition metadata, not expecting further changes.
        beanFactory.freezeConfiguration();

        // Instantiate all remaining (non-lazy-init) singletons.
        //此處beanFactory是DefaultListableBeanFactory,獲取bean
        beanFactory.preInstantiateSingletons();
    }

最后調(diào)用了beanFactory的preInstantiateSingletons方法,此處的beanFactory是DefaultListableBeanFactory。那么我們就看下這個的重點。

List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
    this.logger.info("-----beanName:"+beanName);
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        if (isFactoryBean(beanName)) {
            final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
            boolean isEagerInit;
            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
                        ((SmartFactoryBean<?>) factory).isEagerInit(),
                        getAccessControlContext());
            }
            else {
                isEagerInit = (factory instanceof SmartFactoryBean &&
                        ((SmartFactoryBean<?>) factory).isEagerInit());
            }
            if (isEagerInit) {
                getBean(beanName);
            }
        }
        else {
            /**
             * 核心代碼
             */
            getBean(beanName);
        }
    }
}

在這里看到了熟悉的getBean()方法,別的有興趣和時間再研究吧,先忽略別的,仔細研究getBean()方法,經(jīng)過追蹤發(fā)現(xiàn),他調(diào)用了AbstractoryFactory的doGetBean()方法,這里是一大段的代碼。這里面有太多的代碼,我們先簡單描述,下節(jié)繼續(xù)深入。

//實例化依賴的bean之后可以實例化mbd本身了
//單例模式的創(chuàng)建
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            /**
             *核心創(chuàng)建bean
             */
            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的實現(xiàn),Spring默認(rèn)的bean都是單例的,在此我們看到了createBean()方法,spring源碼寫的確實是比較優(yōu)秀,根據(jù)方法名就能大致的知道其作用。這里的createBean()方法使用的是其子類的方法,這里摘取一點代碼片段看下

/**
 * 鎖定class,根據(jù)設(shè)置的class屬性或者根據(jù)classname來解析class
 */
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    mbdToUse = new RootBeanDefinition(mbd);
    mbdToUse.setBeanClass(resolvedClass);
}

到此bean加載和創(chuàng)建的基本流程也就結(jié)束了,下一篇我們著重會分析一些具體的細節(jié)。

代碼的構(gòu)建請參考 github
該地址有相應(yīng)代碼的注釋

Spring源碼分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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