Spring源碼學習之IOC實現原理(二)-ApplicationContext

来源:http://www.cnblogs.com/ToBeAProgrammer/archive/2016/03/10/5260624.html
-Advertisement-
Play Games

一.Spring核心組件結構 總的來說Spring共有三個核心組件,分別為Core,Context,Bean.三大核心組件的協同工作主要表現在 :Bean是包裝我們應用程式自定義對象Object的,Object中存有數據,而Context就是為了這些數據存放提供一個生存環境,保存各個 bean之間的


一.Spring核心組件結構

     總的來說Spring共有三個核心組件,分別為Core,Context,Bean.三大核心組件的協同工作主要表現在 :Bean是包裝我們應用程式自定義對象Object的,Object中存有數據,而Context就是為了這些數據存放提供一個生存環境,保存各個 bean之間的對應關係,並且維護好這些對應關係。Context就是一個Bean關係的集合,也就是我們所謂的IOC容器。Core就是Context 在發現、建立、維護Bean之間關係所需要的一些工具,如資源的載入,資源的抽象等。 (《深入分析Java Web技術內幕》)

1.Bean組件

      前面介紹的BeanFactory體系就屬於Bean組件,位於org.springframework.beans子包factory包下麵。這個包主要解決三個問題,Bean的定義,Bean的創建,Bean的解析。

beans

1. org.springframework.beans, 包含了操作java bean的介面和類。This package contains interfaces and classes for manipulating Java beans. It is used by most other Spring packages. ***
2. org.springframework.beans.annotation, 支持包,提供對java 5註解處理bean樣式的支持。
3. org.springframework.beans.factory, 實現spring輕量級IoC容器的核心包。***
4. org.springframework.beans.factory.access, 定位和獲取bean工程的輔助工具類。
5. org.springframework.beans.factory.access.el,從統一樣式的EL 獲取spring beanFactory的支持類
6. org.springframework.beans.factory.annotation, 配置基於註解驅動的bean的支持包。***
7. org.springframework.beans.factory.config, bean工廠的SPI介面和配置相關的處理類。
8. org.springframework.beans.factory.parsing, bean definition解析的支持基礎類
9. org.springframework.beans.factory.serviceloader, jdk1.6 ServiceLoader基礎類的支持包。
10. org.springframework.beans.factory.support,org.springframework.beans.factory包的支持類
11. org.springframework.beans.factory.wiring, 一種決定一個bean實例的元數據的機制。
12. org.springframework.beans.factory.xml, 包含了一個基於xml的beanFactory實現,也包含一個標準的spring-beans的dtd
13. org.springframework.beans.propertyeditors, 屬性編輯器,用來將string類型的值轉換為object類型,例如:java.util.Properties
14. org.springframework.beans.support,org.springframework.beans的支持包,像:一組bean的排序和保持工具類等

參考資料spring beans源碼解讀之--總結篇

Bean的定義由BeanDefinition抽象出來,也是IOC容器的內部數據結構。BeanDefinition完整的描述了xml文件中關於<bean>節點的所有信息。當Spring解析一個<bean>節點後,在IOC容器內部就會轉換為BeanDefinition對象。而最終實例化時,所使用的對象就是RootBeanDefinition對象。

BeanDefinition層次關係

圖片引自Spring3.0核心組件的源碼簡單分析

Bean的創建,採用的是典型的工廠模式,採用的體系即(一)中所說的BeanFactory體繫結構。主要的類是DefaultListableBeanFactory,其完整的實現了IOC容器的功能。

Bean的解析,主要就是對於Spring的配置文件進行解析處理,從中解析出相應的信息以用來生成Bean的對象。 其中主要用於解析的實現類就是DefaultBeanDefinitionDocumentReader。

BeanDefinitionReader

2.Core組件

  Core組件作為Spring的核心組件,其中包含了很多關鍵類,一個重要的組成部分就是定義了資源的訪問方式。如之前用到的ClassPathResource就是其中的一個典型的資源抽象形式。資源的頂級介面為Resource,它繼承自InputStreamSource,實現了其getInputStream方法,返回的是InputStream類。這樣所有的資源就是通過該方法來獲取輸入流的。對於資源的載入,也實現了統一,屏蔽了資源提供者。定義了一個資源載入頂級介面 ResourceLoader ,它預設的載入就是DefaultResourceLoader。

Resource

Resource2

2.1InputStreamSource

該介面只有一個抽象方法

public interface InputStreamSource {

    /**
     * Return an {@link InputStream}.
     */
    InputStream getInputStream() throws IOException;

}

2.2 Resource

作為頂級介面,也是再各個類中調用資源時應用最為廣泛的介面,充分體現了面向介面編程的思想。

/**
 * Interface for a resource descriptor that abstracts from the actual
 * type of underlying resource, such as a file or class path resource.
 */
public interface Resource extends InputStreamSource {

    boolean exists();
    boolean isReadable();

    boolean isOpen();

    URL getURL() throws IOException;

    URI getURI() throws IOException;

    File getFile() throws IOException;

    long contentLength() throws IOException;

    long lastModified() throws IOException;

    Resource createRelative(String relativePath) throws IOException;

    String getFilename();

    String getDescription();

}

這就是該介面定義的方法,都是顯而易見的方法,同時也是對於資源類來說應用最多的方法。

2.3ClassPathResource

/**
     * This implementation opens an InputStream for the given class path resource.
     * @see java.lang.ClassLoader#getResourceAsStream(String)
     * @see java.lang.Class#getResourceAsStream(String)
     */
    @Override
    public InputStream getInputStream() throws IOException {
        InputStream is;
        if (this.clazz != null) {
            is = this.clazz.getResourceAsStream(this.path);
        }
        else if (this.classLoader != null) {
            is = this.classLoader.getResourceAsStream(this.path);
        }
        else {
            is = ClassLoader.getSystemResourceAsStream(this.path);
        }
        if (is == null) {
            throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
        }
        return is;
}

該方法就是ClassPathResource的getInputStream方法,可以發現其主要通過class類或者ClassLoader來返回InputStream。而之前的分析可知,當loadBeanDefinition時,最終應用的是InputSource inputSource = new InputSource(inputStream);InputSource,屬於org.xml.sax包,是一個XML形式的輸入流。

3.Context組件

   Context組件在Spring的org.springframework.context包下,它的作用主要是給Spring提供一個運行時的環境,用以保證各個對象的狀態。其中ApplicationContext是Context的頂級父類介面,它除了繼承一個能表示應用環境的基本信息介面外,還繼承了5個介面,這5個介面擴展了Context的功能。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver

appContext

ApplicationContext繼承體系

可以發現其主要應用子類為ClassPathXmlApplicationContext,FileSystemXmlApplicationContext,以及應用在Web上的XmlWebApplicationContext.

二. ApplicationContext源碼詳解

      在ApplicationContext的設計中,一方面可以看到它繼承了BeanFactory介面體繫結構的ListableBeanFactory, HierarchicalBeanFactory,具備了IOC容器的基本功能;另一方面,通過繼承MessageSource, ApplicationEventPublisher, ResourcePatternResolver這些介面,使得其被賦予了更高級別的特性。

1.java doc

/**
 * Central interface to provide configuration for an application.
 * This is read-only while the application is running, but may be
 * reloaded if the implementation supports this.
 *
 * <p>An ApplicationContext provides:
 * <ul>
 * <li>Bean factory methods for accessing application components.
 * Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}.
 * <li>The ability to load file resources in a generic fashion.
 * Inherited from the {@link org.springframework.core.io.ResourceLoader} interface.
 * <li>The ability to publish events to registered listeners.
 * Inherited from the {@link ApplicationEventPublisher} interface.
 * <li>The ability to resolve messages, supporting internationalization.
 * Inherited from the {@link MessageSource} interface.
 * <li>Inheritance from a parent context. Definitions in a descendant context
 * will always take priority. This means, for example, that a single parent
 * context can be used by an entire web application, while each servlet has
 * its own child context that is independent of that of any other servlet.
 * </ul>
 *
 * <p>In addition to standard {@link org.springframework.beans.factory.BeanFactory}
 * lifecycle capabilities, ApplicationContext implementations detect and invoke
 * {@link ApplicationContextAware} beans as well as {@link ResourceLoaderAware},
 * {@link ApplicationEventPublisherAware} and {@link MessageSourceAware} beans.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see ConfigurableApplicationContext
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.core.io.ResourceLoader
 */

ApplicationContext添加的功能主要表現在 :

    1)可以支持不同的信息源,它擴展了MessageSource,支持國際化。

    2)訪問資源,主要就是ResourceLoader的繼承,這樣可以從不同地方得到bean定義的資源。 

    3)支持應用事件,繼承了ApplicationEventPublisher, 這樣在上下文中引入了事件機制。

2.源碼

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

    /**
     * Return the unique id of this application context.
     * @return the unique id of the context, or {@code null} if none
     *///返回標誌Context的Id編號 
    String getId();

    /**
     * Return a name for the deployed application that this context belongs to.
     * @return a name for the deployed application, or the empty String by default
     */
                //返回context所屬應用名稱
    String getApplicationName();

    /**
     * Return a friendly name for this context.
     * @return a display name for this context (never {@code null})
     */
    String getDisplayName();

    /**
     * Return the timestamp when this context was first loaded.
     * @return the timestamp (ms) when this context was first loaded
     */
                //返回loaded時間戳
    long getStartupDate();

    /**
     * Return the parent context, or {@code null} if there is no parent
     * and this is the root of the context hierarchy.
     * @return the parent context, or {@code null} if there is no parent
     */
               //返回雙親ApplicationContext,證明這裡是有層次關係的
    ApplicationContext getParent();

    /**
     * Expose AutowireCapableBeanFactory functionality for this context.
     * <p>This is not typically used by application code, except for the purpose of
     * initializing bean instances that live outside of the application context,
     * applying the Spring bean lifecycle (fully or partly) to them.
     * <p>Alternatively, the internal BeanFactory exposed by the
     * {@link ConfigurableApplicationContext} interface offers access to the
     * {@link AutowireCapableBeanFactory} interface too. The present method mainly
     * serves as a convenient, specific facility on the ApplicationContext interface.
     * <p><b>NOTE: As of 4.2, this method will consistently throw IllegalStateException
     * after the application context has been closed.</b> In current Spring Framework
     * versions, only refreshable application contexts behave that way; as of 4.2,
     * all application context implementations will be required to comply.
     * @return the AutowireCapableBeanFactory for this context
     * @throws IllegalStateException if the context does not support the
     * {@link AutowireCapableBeanFactory} interface, or does not hold an
     * autowire-capable bean factory yet (e.g. if {@code refresh()} has
     * never been called), or if the context has been closed already
     * @see ConfigurableApplicationContext#refresh()
     * @see ConfigurableApplicationContext#getBeanFactory()
     */
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

}

3.*****單步調試ApplicationContext****

仍然採用上一節所使用的例子

ApplicationContext appContext=new ClassPathXmlApplicationContext("beans.xml");
Performer performer=(Performer) appContext.getBean("dancer");
performer.perform();

(1)ApplicationContext appContext=new ClassPathXmlApplicationContext("beans.xml");

調用構造器

/**
     * Create a new ClassPathXmlApplicationContext, loading the definitions
     * from the given XML file and automatically refreshing the context.
     * @param configLocation resource location
     * @throws BeansException if context creation failed
     */
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

可以看到除了load xml定義文件外,還有自動刷新的作用。

第二個boolean參數,是refresh啟動參數。

/**
     * Create a new ClassPathXmlApplicationContext with the given parent,
     * loading the definitions from the given XML files.
     * @param configLocations array of resource locations
     * @param refresh whether to automatically refresh the context,
     * loading all bean definitions and creating all singletons.
     * Alternatively, call refresh manually after further configuring the context.
     * @param parent the parent context
     * @throws BeansException if context creation failed
     * @see #refresh()
     */
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

super(parent),通過逐層向上,最後會到AbstractApplicationContext.

AbstractApplicationContext

回到上面可以看到refresh()方法即為IOC容器初始化的方法,標志著IOC容器的啟動。

setConfigLocations(configLocations),設置資源屬性數組

/**
     * Set the config locations for this application context.
     * <p>If not set, the implementation may use a default as appropriate.
     */
    public void setConfigLocations(String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

(2)refresh()

該方法屬於AbstractApplicationContext,即第一個抽象類。

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //調用容器準備刷新的方法,獲取容器的當時時間,同時給容器設置同步標識 ,log信息也是源自於這個方法
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            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.
                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.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

2.1    prepareRefresh();

為刷新Context前做準備,設定啟動時間,同時Log信息同樣源自這個方法。

/**
     * Prepare this context for refreshing, setting its startup date and
     * active flag as well as performing any initialization of property sources.
     */
    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.active.set(true);

        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }

        // Initialize any placeholder property sources in the context environment
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();
    }

log

2.2ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

刷新所有的BeanFactory子容器,同時這裡涉及到瞭解析和載入BeanDefinition的步驟。

obtainFreshBeanFactory

下麵就分析一下BeanFactory的刷新方法refreshBeanFactory()

這裡應用了委派模式,因為refreshBeanFactory()方法屬於其子類AbstractRefreshApplicationContext.

/**
     * This implementation performs an actual refresh of this context's underlying
     * bean factory, shutting down the previous bean factory (if any) and
     * initializing a fresh bean factory for the next phase of the context's lifecycle.
     */
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
//對IoC容器進行定製化,如設置啟動參數,開啟註解的自動裝配等
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

1.這裡可以看到一個構建DefaultListableBeanFactory容器的過程,先是構造BeanFactory,createBeanFactory()。

2.loadBeanDefinitions(beanFactory),這裡載入了beanDefinition。

接下來再深入loadBeanDefinition(beanFactory)方法

該方法屬於AbstractXmlApplicationContext,又是一個委派模式,讓子類來實現。

/**
     * Loads the bean definitions via an XmlBeanDefinitionReader.
     * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
     * @see #initBeanDefinitionReader
     * @see #loadBeanDefinitions
     */
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

1.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 這個與(一)中分析的過程一樣,同樣是創建了一個可以載入BeanDefinition的讀寫器,同樣用DefaultListableBeanFactory作為構造器參數,從而賦予registy屬性。

2.調用loadBeanDefinitions()

/**
     * Load the bean definitions with the given XmlBeanDefinitionReader.
     * <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory}
     * method; hence this method is just supposed to load and/or register bean definitions.
     * @param reader the XmlBeanDefinitionReader to use
     * @throws BeansException in case of bean registration errors
     * @throws IOException if the required XML document isn't found
     * @see #refreshBeanFactory
     * @see #getConfigLocations
     * @see #getResources
     * @see #getResourcePatternResolver
     */
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

最終調用reader.loadBeanDefinitions(configLocations);這就又回到了(一)IOC容器初始化的過程。

到這裡就完成了BeanDefinition的載入,註冊工作。並且最終返回了DefaultListableBeanFactory,所以BeanDefinition持有容器依然是DefaultListableBeanFactory.所以接下來的工作就應該是實例化工作。

2.3  prepareBeanFactory(beanFactory);

這是在實例化之前進行的工作。

創建好beanFactory後,添加Spring本身需要的工具類。為容器配備了ClassLoader,PropertyEditor和BeanPostProcessor.

/**
     * Configure the factory's standard context characteristics,
     * such as the context's ClassLoader and post-processors.
     * @param beanFactory the BeanFactory to configure
     */
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    //.......
    }

這裡可以看到,ApplicationContextAwareProcessor作為BeanPostProcessor的實現,在這裡添加。

其主要作用是當Bean實現了ApplicationContextAware介面後,當該Bean完成實例化依賴註入之後,會通過BeanPostProcessor的方式來給該Bean註入當前的ApplicationContext.從而使得該實例有能力獲得ApplicationContext.

2.4 postProcessBeanFactory(beanFactory);

這個方法是預留方法,是用來對BeanFactory進行後處理的方法。

2.5 invokeBeanFactoryPostProcessors(beanFactory);

調用所有註冊的BeanFactoryPostProcessor的Bean,這裡也是針對BeanFactory的後置處理器的調用。
2.6 registerBeanPostProcessors(beanFactory);
BeanPostProcessor是Bean後置處理器,用於監聽容器觸發的事件,Bean的後置處理器。Register bean processors that intercept bean creation.這個註冊主要是綁定到DefaultListableBeanFactory中取。
後置處理器向容器註冊以後,容器中管理的Bean就具備了接收IoC容器事件回調的能力。
BeanPostProcessor是一個介面類,主要有兩個方法,一個是postProcessBeforeInitialization,在Bean的初始化前提供回調入口;另一個是postProcessAfterInitialization,在Bean的初始化後提供回調入口。實際上,這兩個後置處理器方法是一前一後圍繞著Bean定義的init-method方法調用的,都是發生在populateBean()方法之後,即完成依賴註入之後發生的。
 
上面其實涉及到了兩個Spring的擴展點,一個是BeanFactoryPostProcessor和BeanPostProcessor,他們分別在構建BeanFactory和構建Bean對象時調用,還有就是InitializationBean和DisposableBean,他們分別在Bean實例創建和銷毀時被調用。
2.7   initMessageSource()和 initApplicationEventMulticaster();
初始化信息源和事件傳播器。
這是由於ApplicationContext分別實現了MessageSource, ApplicationEventPublisher兩個介面。
2.8 finishBeanFactoryInitialization(beanFactory)
完成BeanFactory的初始化工作,這裡涉及到了對於lazy-init屬性的處理。
/**
     * Finish the initialization of this context's bean factory,
     * initializing all remaining singleton beans.
     */
    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));
        }

        // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        for (String weaverAwareName : weaverAwareNames) {
            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.preInstantiateSingletons();
    }

最後一個方法preInstantiateSingletons(),看註釋可知實例化所有的單例,non-lazy-init,即lazy-init屬性為false,而由於其預設屬性就是false,所以這裡會實例化所有的單例。

@Override
    public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        // Iterate over a copy to allow for init methods which in turn register new bean definitions.
        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

        // Trigger initialization of all non-lazy singleton beans...
        for (String beanName : beanNames) {
            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(new PrivilegedAction<Boolean>() {
                            @Override
                            public Boolean run() {
                                return ((SmartFactoryBean<?>) factory).isEagerInit();
                            }
                        }, getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
                else {
                    getBean(beanName);
                }
            }
        }

        // Trigger post-initialization callback for all applicable beans...
        for (String beanName : beanNames) {
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) {
                final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public Object run() {
                            smartSingleton.afterSingletonsInstantiated();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()),從這句代碼可以看出當BeanDefinition不是抽象類,是單例類,lazyinit屬性為false時,則預實例化,其不為FactoryBean時調用getBean()方法。

其BeanDefinition定義如下:Root bean: class [com.wly.source.spring_scoure_inspect.Dancer]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [beans.xml]

所以這裡就完成了預實例化的過程。

2.9 finishRefresh()

初始化容器的生命周期事件處理器,併發布容器的生命周期事件。
/**
     * Finish the refresh of this context, invoking the LifecycleProcessor's
     * onRefresh() method and publishing the
     * {@link org.springframework.context.event.ContextRefreshedEvent}.
     */
    protected void finishRefresh() {
        // Initialize lifecycle processor for this context.
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在寫一個struts2+hibernate整合的小例子時,啟動Tomcat伺服器,報了一個: 嚴重: Exception starting filter struts2java.lang.ClassNotFoundException: org.apache.struts2.dispatcher.ng
  • 1.跳轉到任一UIViewController var sb = UIStoryboard(name: "Main", bundle:nil) var vc = sb.instantiateViewControllerWithIdentifier("ChooseViewController") as
  • 就在這個鏈接中:http://liangfangli86.blog.163.com/blog/static/9684863120116183727729/ 當然,我們經常使用的是快捷鍵:Ctrl+Shift+F 其中F不是在搜狗輸入法的情況下輸入的
  • 國外程式員ziadoz 在Github上收集整理了PHP的各種資源,內容包括模板、框架、資料庫、安全等方面的庫和工具。這篇文章,PHP100彙總了這些PHP資源,供各位PHP學習者和程式員參考。廢話不多說,下麵就是詳細的資料列表。 依賴管理 ——用於依賴管理的包和框架 Composer/Packag
  • 手動刪除webapps下項目,導致Document base D:\Server\apache-tomcat-7.0.61_x64\webapps\XXX does not exist or is not a readable
  • 如何利用php自動執行.sql文件,就是獲取sql文件中的內容,然後將每一句sql語句一次執行。 代碼example: //讀取文件內容 $_sql = file_get_contents('test.sql'); $_arr = explode(';', $_sql); $_mysqli = ne
  • 剛剛學完這兩個框架,就迫不及待的做了一個例子,在整合兩個框架的時候,也碰到了一些小問題,下麵介紹一下配置的步驟: 1.創建一個自定義的struts2和hibernate的類庫 因為之前寫例子都是直接將jar包拖到WEB-INF下的lib包下,但是這裡需要導入兩個框架的jar包,放在一起的話,會很亂,
  • meta基礎知識 常見問題 常用的移動端框架 iscroll.js underscore.js 滑屏框架 FastClick meta基礎知識 H5頁面視窗自動調整到設備寬度,並禁止用戶縮放頁面 <meta name="viewport" content="width=device-width,in
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...