Springソース(四)-beanのロード(上)

10681 ワード

前言


前にcontextの作成についてお話ししましたが、これからコアのbeanの作成過程に入ります.前期の準備が完了しました.多くの人が私と同じように、一度見たことがあるのは大体の印象しかありません.これから時間があれば、UMLと脳図を組み合わせてみんなと一緒に分かち合い、経験があるか、一緒に勉強したいと思っています.私に連絡してください.qq:616516146、本題に戻って、コードに戻ります.

1、prepareContext()


次に最初のコードSpringApplicationのrunメソッドに戻り、prepareContext()というメソッドを見てみましょう.この方法はcontextの準備をすることです.コードに入って彼の具体的な実装を見てみましょう.
    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        /**
         *  context , ResourceLoader ClassLoader,
         *  bean beanNameGenerator
         */

        postProcessApplicationContext(context);
        /**
         *
         * applyInitializers(context) 
         *  spring SpringApplication.setInitializers(xxx)
         *  
         */
        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 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[sourcess.size()]))の3つの方法についてのみ議論する.
  • 1、postProcessApplicationContext(context)このメソッドはcontextを事前設定し、ResourceLoaderとClassLoaderを設定し、beanファクトリにbeanName Generator
  • を追加した.
  • 2、applyInitializers(context)この方法は私たちまたはspringがSpringApplicationを通じて取得した.setInitializers(xxx)設定のアプリケーションコンテキストイニシエータセット.
  • 3、load(context,sources.toArray(new Object[sources.size()))この方法は主に各種beansをcontextオブジェクトにロードする.sourcesは様々なリソースオブジェクトを表し、BeanDefinitionLoaderの内部は様々な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
         *  xxxReader xxxScanner 、 beans。
         *      BeanDefinitionLoader 
         */
        protected void load(ApplicationContext context, Object[] sources) {
            logger.debug(" load ");
            System.out.println("------------- load ");
            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メソッドのロードです.上記の3つの方法が完了すると、prepareContext()関数はrefreshコンテキストの基礎的な準備ができています.次にrefreshに関する仕事を見ます.

    2、refresh

    private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                /**
                 *  context 
                 */
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }
    

    ここではrefreshに入って具体的な実装を見てみましょう.ここでrefreshはAbstractApplicationContextのrefreshメソッドを呼び出し、その後contextを呼び出します.registerShutdownHook();フックを閉じた.AbstractApplicationContextに入り、refreshの具体的な実装を見て、ここではコードの一部だけを切り取った.
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();
        // Tell the subclass to refresh the internal bean factory.
        //BeanFactory 
        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( ) 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();
        }
    
    

    ここでは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);
                // 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();
        }
    
    

    最後にbeanFactoryのpreInstantiateSingletonsメソッドが呼び出され、ここでbeanFactoryはDefaultListableBeanFactoryです.では、これのポイントを見てみましょう.
    List 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) () ->
                            ((SmartFactoryBean>) factory).isEagerInit(),
                            getAccessControlContext());
                }
                else {
                    isEagerInit = (factory instanceof SmartFactoryBean &&
                            ((SmartFactoryBean>) factory).isEagerInit());
                }
                if (isEagerInit) {
                    getBean(beanName);
                }
            }
            else {
                /**
                 *  
                 */
                getBean(beanName);
            }
        }
    }
    

    ここではおなじみのgetBean()メソッドを見ましたが、他に興味と時間があったら検討しましょう.まず他を無視してgetBean()メソッドをよく研究し、追跡してみるとAbstractoryFactoryのdoGetBean()メソッドを呼び出しました.ここは大きなコードです.この中には多くのコードが入っています.まず簡単に説明し、次の節に進みます.
    // bean mbd 
    // 
    if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, () -> {
            try {
                /**
                 * 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の実装,Springデフォルトのbeanはいずれも単例であるが,ここではcreateBean()メソッドを見たが,springソースコードは確かに優れており,メソッド名によってその役割を大まかに知ることができる.ここのcreateBean()メソッドはそのサブクラスのメソッドを使用しています.ここではコードクリップを少し取り出して見てください.
    /**
     *  class, class classname class
     */
    Class> resolvedClass = resolveBeanClass(mbd, beanName);
    
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
    

    ここでbeanのロードと作成の基本プロセスも終わり、次の記事では具体的な詳細を分析することに重点を置きます.
    コードの構築はgithubを参照してください.このアドレスには対応するコードのコメントがあります.

    Springソース分析

  • 1、Springソースコード(一)-spring全体アーキテクチャと環境構築
  • 2、Springソースコード(二)-Contextの作成(上)
  • 3、Springソースコード(三)-Contextの作成(下)