Spring之一:IoC容器體系結構

溫故而知心。html

Spring IoC概述

常說spring的控制反轉(依賴反轉),看看維基百科的解釋:java

若是合做對象的引用或依賴關係的管理要由具體對象來完成,會致使代碼的高度耦合和可測試性下降,這對複雜的面向對象系統的設計使很是不利的。node

在面向對象系統中,對象封裝了數據和對數據的處理,對象的依賴關係經常體如今對數據和方法的依賴上。這些依賴關係能夠經過把對象的依賴注入交給框架或者IoC容器來完成,這種從具體對象手中交出控制的作法是很是有價值的,它能夠在解耦代碼的同時提升代碼的可測試性。算法

IoC容器的規範接口BeanFactory

做爲IoC容器,也須要爲它的具體實現指定基本的功能規範,這個功能規範的設計表現爲接口類BeanFactory,它體現了Spring爲提供給用戶使用的IoC容器所設定的最基本功能規範。spring

BeanDefinition

Spring經過定義BeanDefinition來管理基於Spring的應用中的各類對象以及它們之間的相互依賴關係。BeanDefinition抽象了咱們對Bean的定義,是讓容器起做用的主要數據類型。IoC容器是用來管理對象依賴關係的,對IoC容器來講,BeanDefinition就是對依賴反轉模式中管理的對象依賴關係的數據抽象,也是容器實現依賴反轉功能的核心數據結構,依賴反轉功能都是圍繞對這個BeanDefinition的處理上完成的編程

BeanFactory和ApplicationContext之間區別

弄清楚這兩種重要容器之間的區別和聯繫,意味着咱們具有辨別容器系列中不一樣容器產品的能力。還有一個好處就是,若是須要定製特定功能的容器實現,也能比較方便的在容器系列中找到一款恰當的產品做爲參考。設計模式

從前面咱們知道,BeanFactory定義了IoC容器的基本功能規範,全部,下面咱們就從BeanFactory這個最基本的容器定義來進入Spring的IoC容器體系,去了解IoC容器的實現原理。緩存

BeanFactory定義了IoC容器的最基本形式,而且提供了IoC容器所應該遵照的最基本的服務契約。在Spring的代碼中,BeanFactory只是一個接口類,並無給出容器的具體實現,具體類能夠上前面的截圖,如DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等均可以當作是容器的附加了某種功能的具體實現,也就是容器體系中的具體容器產品。數據結構

 用戶使用容器時,可使用轉義符「&」來獲得FactoryBean自己,用來區別經過容器獲取FactoryBean產生的對象和獲取FactoryBean自己。(舉例說明:myJndiObject是一個FactoryBean,那麼使用&myJndiObject獲得的是FactoryBean,而不是myJndiObject這個FactoryBean產生出來的對象)。app

注意:理解上面這段話須要很好的區分FactoryBean和BeanFactory這兩個再spring中使用頻率很高的類,他們在拼寫上很是類似,

  • BeanFactory:是Factory,也就是IoC容器或者對象工廠;
  • FactoryBean:是Bean,在spring中,全部Bean都是用BeanFactory(也就是IoC容器)來進行管理的。對FactoryBean而言,這個bean不是簡單的Bean,而是一個能產生或者修飾對象生產的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式相似。

BeanFactory與FactoryBean的區別見《Spring之1:的BeanFactory和FactoryBean

BeanFactory的繼承提現,AutowireCapableBeanFactory-->AbstractAutowireCapableBeanFactory-->DefaultListableBeanFactory-->XmlBeanFactory IoC容器的實現系列。

從這個容器系列的最底層實現XmlBeanFactory開始,這個容器的實現與咱們在Spring應用中用到的那些上下文對比,有一個明顯的特色,它只提供了最基本的IoC容器的功能。從它的名字中能夠看出,這個IoC容器能夠讀取以XML形式定義的BeanDefinition。能夠認爲XmlBeanFactory實現是IoC容器的基本形式,而各類ApplicationContext的實現是IoC容器的高級形式。

XmlBeanFactory的源碼:

public class XmlBeanFactory extends DefaultListableBeanFactory {

    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }

}

  XmlBeanFactory是一個與XML相關的BeanFactory,也就是說它能夠讀取以XML文件方式定義的BeanDefinition的一個IoC容器。對這些XML文件定義信息的處理由其定義的XmlBeanDefinitionReader對象,有了這個reader對象,那些以XML的方式定義的BeanDefinition就有了處理的地方。咱們能夠看到,對這些XML形式的信息的處理其實是由這個XmlBeanDefinitionReader來完成的。

  參考XmlBeanFactory的實現,咱們能夠以編程的方式使用DefaultListableBeanFactory。

例如:編程方式使用IoC容器:更多的見《Spring之A:Spring Bean動態註冊、刪除

ApplicationContext ctx = SpringApplication.run(Application.class, args);

        // 獲取BeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) ctx
                .getAutowireCapableBeanFactory();

        // 建立bean信息.
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TestService.class);
        beanDefinitionBuilder.addPropertyValue("name", "張三");

        // 動態註冊bean.
        defaultListableBeanFactory.registerBeanDefinition("testService", beanDefinitionBuilder.getBeanDefinition());

  在IoC容器實現中的那些關鍵的類(好比Resource、DefaultListableBeanFactory以及BeanDefinitionReader)之間的相互關係,能夠看出其功能解耦的做用。在使用IoC容器時,須要以下幾個步驟:

  1. 建立IoC配置文件的抽象資源,這個抽象資源包含了BeanDefinition的定義信息。
  2. 建立一個BeanFactory,這裏使用DefaultListableBeanFactory。
  3. 建立一個載入BeanDefinition的讀取器,能夠用BeanDefinitionBuilder或者XmlBeanDefinitionReader來載入XML文件形式的BeanDefinition,經過一個回調配置給BeanFactory。
  4. 從定義好的資源位置讀入配置信息,具體的解析過程由XmlBeanDefinitionReader來完成。完成整個載入和註冊Bean定義以後,須要的IoC容器就創建起來了。這個時候IoC容器就能夠直接使用了。

ApplicationContext

 在Spring中系統已經爲用戶提供了許多已經定義好的容器實現,而不須要開發人員事必躬親。相比那些簡單拓展BeanFactory的基本IoC容器,其中ApplicationContext是推薦的BeanFactory,由於除了能提供容器的基本功能外,還爲用戶提供了更多的附加服務。

 見《Spring之3:BeanFactory、ApplicationContext、ApplicationContextAware區別

 

3、IoC容器初始化

  IoC容器的初始化包括BeanDefinition的Resource定位、載入和註冊這三個基本的過程。在《Spring之2:Spring Bean動態註冊、刪除》中,咱們演示了這三個過程的實現。Spring在實現中把這三個過程分開並使用不一樣的模塊來完成的,這樣可讓用戶更加靈活地對這三個過程進行剪裁和擴展,定義出最適合本身的IoC容器的初始化過程

1、Resource定位。BeanDefinition的資源定位有resourceLoader經過統一的Resource接口來完成,這個Resource對各類形式的BeanDefinition的使用提供了統一接口。對於這些BeanDefinition的存在形式,相信不陌生,如:

FileSystemResource、ClassPathResource。這個過程相似於容器尋找數據的過程,就像用水桶裝水要把水找到同樣。

2、第二個關鍵的部分是BeanDefinition的載入,該載入過程把用戶定義好的Bean表示成IoC容器內部的數據結構,而這個容器內部的數據結構就是BeanDefinition。簡單說,BeanDefinition其實是POJO對象在IoC容器中的抽象,這個BeanDefinition定義了一系列的數據來使得IoC容器可以方便地對POJO對象也就是Spring的Bean進行管理。即BeanDefinition就是Spring的領域對象。

3、第三個過程是向IoC容器註冊這些BeanDefinition的過程。這個過程是經過調用BeanDefinitionRegistry接口的實現來完成的,這個註冊過程把載入過程當中解析獲得的BeanDefinition向IoC容器進行註冊。能夠看到,在IoC容器內部,是經過使用一個HashMap來持有BeanDefinition數據的。

3.一、BeanDefinition的Resource定位

  回到咱們常用的ApplicationContext上來,例如FileSystemXmlApplicationContext、ClassPathXmlApplicationContext以及XmlWebApplicationContext等。簡單地從這些類的名字上分析,能夠清楚地看到它們能夠提供哪些不一樣的Resource讀入功能,

  • FileSystemXmlApplicationContext能夠從文件系統載入Resource
  • ClassPathXmlApplicationContext能夠從Class path載入Resource
  • XmlWebApplicationContext能夠在Web容器中載入Resource

 FileSystemXmlApplicationContext的類層級關係:

FileSystemXmlApplicationContext extends AbstractXmlApplicationContext,具有了ResourceLoacer讀入Resource定義的BeanDefinition的能力,由於AbstractXmlApplicationContext的基類是DefaultResourceLoader(AbstractApplicationContext extends DefaultResourceLoader)。FileSystemXmlApplicationContext是一個支持XML定義BeanDefinition的ApplicationContext,而且能夠指定以文件形式的BeanDefinition的讀入,這些文件可使用文件路徑和URL定義來表示。這個在單元測試時,很是有用。

FileSystemXmlApplicationContext.java源碼
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

    public FileSystemXmlApplicationContext() {
    }

    public FileSystemXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }

    /**
     * 這個構造函數的configLocation包含的是BeanDefinition所在的文件路徑
     */
    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

    /**
     * 這個構造函數容許configLocation包含多個BeanDefinition的文件路徑
     */
    public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, null);
    }

    /**
     * 這個構造函數在容許configLocation包含多個BeanDefinition的文件路徑的同時,還容許指定本身的雙親IoC容器
     */
    public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
        this(configLocations, refresh, null);
    }

    /**
     * 在對象的初始化過程當中,調用refresh函數載入BeanDefinition,這個refresh啓動了BeanDefinition的載入過程,咱們會在下面進行詳細分析
     */
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

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


    /**
     * 這是應用於文件系統中Resource的實現,經過構造一個FileSystemResource來獲得一個在文件系統中定位的BeanDefinition
     * 這個getResourceByPath是在BeanDefinitionReader的loadBeanDefinition中被調用的。
     * loadBeanDefinition採用了模板模式,具體的定位實現其實是由各個子類完成的
     */
    @Override
    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }

}

 構造函數中經過refresh()中啓動IoC容器的初始化,這個refresh方法很是重要,也是咱們之後分析容器初始化過程的一個重要入口。

BeanDefinition信息的讀入

FileSystemXmlApplicationContext的基類AbstractRefreshableApplicationContext,重點看看AbstractRefreshableApplicationContext的refreshBeanFactory()方法,
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
                        //IoC容器是DefaultListableBeanFactory
            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);
        }
    }

 在初始化FileSystemXmlApplicationContext的過程當中,經過IoC容器的初始化refresh來啓動整個應用,使用IoC容器的是DefaultListableBeanFactory。具體資源加載是在XmlBeanDefinitionReader讀入BeanDefinition時完成,在XmlBeanDefinitionReader的基類AbstractBeanDefinitionReader中可看到這個載入過程的具體實現。

    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        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;
        }
    }

對載入過程的啓動,能夠在AbstractRefreshableApplicationContext的loadBeanDefinition方法中看到

AbstractRefreshableApplicationContext對容器的初始化

@Override
    protected final void refreshBeanFactory() throws BeansException {
        //判斷,若是已經創建了BeanFactory,則銷燬並關閉該BeanFactory
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        //這裏是建立並設置特有的DefaultListableBeanFactor的地方。
        //同時調用loadBeanDefinition在載入BeanDefinition的信息。
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            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);
        }
    }

建立DefaultListableBeanFactory實例

    /**
    *這就是上下文中建立DefaultListableBeanFactory的地方,而getInternalParentBeanFactory()的具體實現能夠參看AbstractApplicationCtontext中的實現,會根據容器已有的雙親IoC容器的信息來生成DefaultListableBeanFactory的雙親IoC容器
    */
    protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }

 getInernalParentBeanFactory,會根據容器已有的雙親IoC容器的信息來生成DefaultListableBeanFactory的雙親IoC容器

    protected BeanFactory getInternalParentBeanFactory() {
        return (getParent() instanceof ConfigurableApplicationContext) ?
                ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
    }

 loadBeanDefinition()是一個抽象函數把具體實現委託給子類來完成,容許載入的方式有不少種:

    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
            throws BeansException, IOException;

 3.二、BeanDefinition的載入和解析

  對於IoC容器來講,BeanDefinition的載入過程至關於把咱們定義的BeanDefinition在IoC容器中轉化成一個Spring內部表示的數據結構的過程。IoC容器對Bean的管理和依賴注入功能的實現,是經過對其持有的BeanDefinition進行各類相關的操做來完成的。這些BeanDefinition數據在IoC容器裏經過一個HashMap來保持和維護,固然這只是一種比較簡單的維護方式,若是你以爲須要提供IoC容器的性能和容量,徹底能夠本身作一些擴展。

  能夠從DefaultListableBeanFactory入手看看IoC容器是怎樣完成BeanDefinition載入的。

    /**
     * 在對象的初始化過程當中,調用refresh函數載入BeanDefinition,這個refresh啓動了BeanDefinition的載入過程,咱們會在下面進行詳細分析
     */
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
       //這裏調用容器的refresh,是載入BeanDefinition的入口。
        if (refresh) {
            refresh();
        }
    }

 refresh方法,對容器啓動來講,很是重要。它詳細描述了整個ApplicationContext的初始化過程,好比BeanFactory的更新,messagesource和postprocessor的註冊,等等。這裏看起來更像是對ApplicationContext進行初始化的模板或執行大綱,這個執行過程爲IoC容器Bean的什麼週期管理提供了條件。IoC容器的refresh過程以下:

AbstractApplicationContext.refresh()

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
                    //這裏是在子類中啓動refreshBeanFactory()的地方,在obtainFreshBeanFactory()裏調用refreshBeanFactory()
            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) {
                if (logger.isWarnEnabled()) {
                    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;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

咱們進入到AbstractRefreshableApplicationContext的refreshBeanFactory()方法中,在這個方法裏建立了BeanFactory。

@Override
    protected final void refreshBeanFactory() throws BeansException {
        //判斷,若是已經創建了BeanFactory,則銷燬並關閉該BeanFactory
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        //這裏是建立並設置特有的DefaultListableBeanFactor的地方。
        //同時調用loadBeanDefinition在載入BeanDefinition的信息。
        try {
            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);
        }
    }

這裏調用的loadBeanDefinitions(beanFactory)是一個抽象方法,那麼實際載入過程是在哪裏發送的呢?

看看AbstractXmlApplicationContext中的實現:

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        //建立XmlBeanDefinitionReader,並經過回調設置到BeanFactory中取
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        //這裏設置XmlBeanDefinitionReader,爲XmlBeanDefinitionReader配置ResourceLoader,由於DefaultResourceLoader是父類,全部this能夠直接被使用。
        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.
        //這是啓動Bean定義信息載入的過程
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

接着看loadBeanDefinitions(XmlBeanDefinitionReader reader)方法

AbstractXmlApplicationContext.loadBeanDefinitions(XmlBeanDefinitionReader reader)方法:首先獲得BeanDefinition信息的Resource定位,而後直接調用XmlBeanDefinitionReader讀取具體的載入過程是委託給BeanDefinitionReader來完成的。

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
                //首先獲得BeanDefinition信息的Resource定位
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
                        //調用BeanDefinitionReader讀取BeanDefinition信息
            reader.loadBeanDefinitions(configResources);
        }
                //下面相似,只是這裏是多個Resource場景
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

 經過上面實現原理分析,咱們能夠看到,在初始化FileSystemXmlApplicationContext的過程當中,是經過調用IoC容器的refresh來啓動整個BeanDefinition的載入過程的,這個初始化是經過定義的XmlBeanDefinitionReader來完成的。

同時,咱們也知道實際使用的IoC容器是DefaultListableBeanFactory,具體的Resource載入在XmlBeanDefinitionReader讀入BeanDefinition時實現。

由於Spring能夠對應不一樣形式的BeanDefinition。上面講的是XML方式定義場景,因此須要使用XmlBeanDefinitionReader。

AbstractBeanDefinitionReader.loadBeanDefinitions(Resource... resources)

    @Override
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        //若是Resource爲空,則中止BeanDefinition的載入。
        //而後啓動載入BeanDefinition的過程,這個過程會遍歷整個Resource集合所包含的BeanDefnition信息。
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        for (Resource resource : resources) {
            counter += loadBeanDefinitions(resource);
        }
        return counter;
    }

 這裏調用的是loadBeanDefinitions(Resource resource)方法,然而這個方法在AbstractBeanDefinitionReader接口裏沒有實現,是一個接口方法,具體的實如今XmlBeanDefinitionReader中,在讀取器中,須要獲得表明XML文件的Resource,由於這個Resource對象封裝了對XML文件的IO操做,因此讀取器能夠在打開IO流後獲得XML的文件對象。有了這個Document對象後,就能夠按照Spring的Bean定義規則來對這個XML的文檔樹進行解析了,這個解析時交給BeanDefinitionParserDelegate來完成的,看起來實現脈絡很清楚。具體實現代碼:

XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource)和loadBeanDefinitions(EncodedResource encodedResource):

    //這裏是調用的入口
        public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(new EncodedResource(resource));
    }
        //這裏是載入XML形式的BeanDefinition的地方。
    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
                //這裏獲得XML文件,並獲得IO的InputSource準備進行讀取。
        try {
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }
        //具體的讀取過程能夠在doLoadBeanDefinitions方法中找到。
        //這是從特定的XML文件中實際載入BeanDefinition的地方。
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            Document doc = doLoadDocument(inputSource, resource);
//這裏啓動的是對BeanDefinition解析的詳細過程,這個解析會使用到Spring的Bean配置規則,是咱們下面詳細關注的地方。
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); } }

 

    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        //這裏取得XML文件的Document對象,這個解析過程是有documentLoader完成的,
       //這個documentLoader是DefaultDocmentLoader,在定義documentLoader的地方建立
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                getValidationModeForResource(resource), isNamespaceAware());
    }

DefaultDocumentLoader.loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware)方法:

    public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        return builder.parse(inputSource);
    }

 下面看看Spring的BeanDefinition是怎樣按照Spring的Bean語義要求進行解析並轉化爲容器內部數據結構的,這個過程是在registerBeanDefinitions(doc, resource)完成的。具體過程是有BeanDefinitionDocumentReader來完成的,這個registerBeanDefinitions(doc, resource)還對載入的Bean的數量進行了統計。具體代碼:

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //這裏獲得BeanDefinitionDocumentReader來對xml的BeanDefinition進行解析
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        //具體解析過程在這個registerBeanDefinitions中完成
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

  BeanDefinition的載入包括兩部分

首先經過調用XML的解析器獲得document對象,但這些document對象並無按照Spring的Bean規則進行解析。在完成通用的XML解析之後,纔是按照Spring的Bean規則進行解析的地方,按照Spring的Bean規則進行解析的過程是在documentReader中實現的。

而後再完成BeanDefinition的處理,處理的結果由BeanDefinitionHolder對象持有。這個BeanDefinitionHolder除了持有BeanDefinition對象外,還持有了其餘與BeanDefinition的使用相關的信息,好比Bean的名字、別名集合等。具體的Spring BeanDefinition的解析是在BeanDefinitionParserDelegate中完成的。這裏包含了各類Spring Bean定義規則的處理。

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        //這裏取得在<Bean>元素中定義的id,name和aliase屬性的值
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        List<String> aliases = new ArrayList<String>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            beanName = aliases.remove(0);
            if (logger.isDebugEnabled()) {
                logger.debug("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            checkNameUniqueness(beanName, aliases, ele);
        }
        //這個方法會引起對bean元素的詳細解析。
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        // Register an alias for the plain bean class name, if still possible,
                        // if the generator returned the class name plus a suffix.
                        // This is expected for Spring 1.2/2.0 backwards compatibility.
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Neither XML 'id' nor 'name' specified - " +
                                "using generated bean name [" + beanName + "]");
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

 咱們看到了對Bean元素進行解析的過程,也就是BeanDefinition依據XML的<bean>定義被建立的過程。這個BeanDefinition能夠當作是<bean>定義的抽象。這個數據對象裏封裝的數據大多數是與<bean>定義相關的,也有不少就是咱們在定義Bean時看到的那些Spring標記,好比init-method、destroy-method、factory-method,等等,這個BeanDefinition數據類型是很是重要的,它封裝了不少基本數據。有了這些基本數據,IoC容器才能對Bean配置進行處理,才能實現相應容器特性。

看起來很熟悉吧,beanClass、description、lazyInit這些屬性都是在配置Bean時常常碰到的,原來都跑道這裏了。BeanDefinition是IoC容器體系中很是重要的核心數據結構。

對BeanDefinition的元素的處理

  在對其處理的過程當中能夠看到對Bean定義的相關處理,好比對元素attribute值的處理,對元素屬性值的處理,對構造函數設置的處理等等。

BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean):

    public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));
               //這裏只讀取定義的<bean>中設置的class名字,而後載入到BeanDefinition中取,只是坐個記錄,並不涉及對象的實例化過程,對象的實例化其實是在依賴注入時完成的。
        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }

        try {
            String parent = null;
            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                parent = ele.getAttribute(PARENT_ATTRIBUTE);
            }
                        //這裏生成須要的BeanDefinition對象,爲Bean定義信息的載入作準備。
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
                       //這裏對當前的Bean元素進行屬性解析,並設置description的信息
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
                       //從名字能夠清楚地看到,這裏是對各類<bean>元素的信息進行解析的地方。
            parseMetaElements(ele, bd);
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
                        //解析<bean>的構造函數設置
            parseConstructorArgElements(ele, bd);
                        //解析<bean>的property設置
            parsePropertyElements(ele, bd);
            parseQualifierElements(ele, bd);

            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));

            return bd;
        }
                 //下面這些異常時咱們在配置bean出問題時常常能夠看到的,原來是在這裏拋出的,
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        catch (NoClassDefFoundError err) {
            error("Class that bean class [" + className + "] depends on not found", ele, err);
        }
        catch (Throwable ex) {
            error("Unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parseState.pop();
        }

        return null;
    }                                

上面是具體生成BeanDefinition的地方。

舉例對property進行解析的例子來完成對整個BeanDefinition載入過程的分析,仍是在類BeanDefinitionParserDelegate的代碼中,它對BeanDefinition中定義一層一層地進行解析,好比從屬性元素集合到具體的每個屬性元素,而後纔是對具體的屬性值的處理。根據解析結果,對這些屬性值的處理會封裝成PropertyValue對象並設置到BeanDefinition對象中去,

    //這裏對指定bean元素的property子元素集合進行解析
    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
                //遍歷全部bean元素下定義的property元素
        NodeList nl = beanEle.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
                                //在上面判斷是property元素後對該property元素進行解析的過程。
                parsePropertyElement((Element) node, bd);
            }
        }
    }

    public void parsePropertyElement(Element ele, BeanDefinition bd) {
                //這裏取得property的名字
        String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
        if (!StringUtils.hasLength(propertyName)) {
            error("Tag 'property' must have a 'name' attribute", ele);
            return;
        }
        this.parseState.push(new PropertyEntry(propertyName));
        try {
                        //若是同一個bean中已經有同名property的存在,則不進行解析,直接返回。也就是說,若是在同一個bean中有同名的property設置,那麼起做用的只是第一個。
            if (bd.getPropertyValues().contains(propertyName)) {
                error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
                return;
            }
                        //這裏是解析property值的地方,返回的對象對應對bean定義的property屬性,設置解析結果,這個解析結果會封裝到PropertyValue對象中,而後設置的解析結果,這個解析結果會封裝到PropertyValue對象中,而後設置到BeanDefinitionHolder中去。
            Object val = parsePropertyValue(ele, bd, propertyName);
            PropertyValue pv = new PropertyValue(propertyName, val);
            parseMetaElements(ele, pv);
            pv.setSource(extractSource(ele));
            bd.getPropertyValues().addPropertyValue(pv);
        }
        finally {
            this.parseState.pop();
        }
    }
        //這裏取得property元素的值,也許是一個list或其餘
    public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
        String elementName = (propertyName != null) ?
                        "<property> element for property '" + propertyName + "'" :
                        "<constructor-arg> element";

        // Should only have one child element: ref, value, list, etc.
        NodeList nl = ele.getChildNodes();
        Element subElement = null;
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
                    !nodeNameEquals(node, META_ELEMENT)) {
                // Child element is what we're looking for.
                if (subElement != null) {
                    error(elementName + " must not contain more than one sub-element", ele);
                }
                else {
                    subElement = (Element) node;
                }
            }
        }

上面是對property子元素的解析過程,Array、List、Set、Map、Prop等各類元素都會在這裏進行解析,生成對應的數據對象,parseArrayElement、parseListElment、parseSetElement、parseMapElement、parsePropElement對應不一樣類型的數據解析。

  通過這樣逐層地解析,咱們在XML文件中定義的BeanDefinition就被整個給載入到了IoC容器中,並在容器中創建了數據映射。在IoC容器中創建了對應的數據結構,或者說能夠當作是POJO對象在IoC容器中的映像,這些數據結構能夠以AbstractBeanDefinition爲入口,讓IoC容器執行索引、查詢和操做。通過上面的載入過程,IoC容器大體完成了管理Bean對象的數據準備工做。如今接着看最重要的依賴注入過程。

3.三、BeanDefinition在IoC容器中的註冊

  上面已經分析了BeanDefinition在IoC容器中載入和解析的過程。在這些動做完成之後,用戶定義的BeanDefinition信息已經在IoC容器內創建起了本身的數據結構以及相應的數據表示,但此時這些數據還不能讓IoC容器直接使用,須要在IoC容器中對這些BeanDefinition數據進行註冊。這個註冊爲IoC容器提供更友好的使用方式。

  DefaultListableBeanFactory中,是經過一個HashMap來持有載入的BeanDefinition的,這個HashMap的定義在DefaultListableBeanFactory能夠看到。以下:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
       //...
    /** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
       //...
}

BeanDefinition註冊的實現,

DefaultListableBeanFactory 繼承了BeanDefinitionRegistry的接口,這個接口的實現完成了BeanDefinition向容器的註冊。這個註冊過程不復雜,就是把解析獲得的BeanDefinition設置到hashMap中取。須要注意的是,若是遇到同名的BeanDefinition的狀況,進行處理的時候須要依據allowBeanDefinitionOverriding的配置來完成。
    //---------------------------------------------------------------------
    // Implementation of BeanDefinitionRegistry interface
    //---------------------------------------------------------------------

    @Override
    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;

        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        //檢查是否是有相同名字的BeanDefinition已經在IoC容器中註冊了,若是有相同名字的BeanDefinition,但又不容許覆蓋,那麼拋出異常。
        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);
        }
        //這是正常註冊BeanDefinition的過程,把Bean的名字存入到BeanDefinitionNames的同時,把beanName做爲Map的key,
        //把beanDefinition做爲value存入到IoC容器持有的beanDefinitionMap中去。
        else {
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                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容器的初始化過程。此時,在咱們使用的IoC容器DefaultListableBeanFactory中已經創建了整個Bean的配置信息,並且這些BeanDefinition已經能夠被容器使用了,他們均可以在beanDefinitionMap裏檢索和使用。

容器的做用就是對這些信息進行處理和維護。這些信息是容器創建依賴反轉的基礎,有了這些基礎數據,下面看在IoC容器中,依賴注入時怎樣完成的。

 4、IoC容器的依賴注入

  假設當前IoC容器已經載入了用戶定義的Bean信息,如今能夠開始分析依賴注入的原理。

 首先,依賴注入的過程是用戶在第一次向IoC容器索要Bean時觸發的(調用BeanFactory的getBean方法時),固然也有例外,也就是咱們能夠在BeanDefinition信息中經過控制lazy-init屬性來讓容器完成對Bean的預實例化。

 爲了瞭解這個依賴注入過程,咱們從DefaultListableBeanFactory的基類AbstractBeanFactory入手去看看getBean的實現。

依賴注入入口

    //---------------------------------------------------------------------
    // Implementation of BeanFactory interface
        //這裏是對BeanFactory接口的實現,好比getBean接口方法
        //這些getBean接口方法最終是經過調用doGetBean來實現的
    //---------------------------------------------------------------------

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }
    //這裏是實際去取bean的地方,也是觸發依賴注入發送的地方。
    protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {

        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        //從緩存中去取,處理已經被建立過的單件模式的bean,對這種bean的請求不須要重複地建立。
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            //這裏的getObjectForBeanInstance完成的是FactoryBean的相關處理,
            //以取得FactoryBean的生產結果,咱們在前面介紹過BeanFactory和FactoryBean的區別
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            //這裏對IoC容器裏的BeanDefinition是否存在進行檢查,檢查是否能在當前的BeanFactory中渠道咱們須要的Bean。
            //若是在當前的工廠中取不到,則到雙親BeanFactory中去取;若是當前的雙親工廠取不到,那就順着雙親BeanFactory鏈一直向上查找。
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }
                      //
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
                 //這裏根據bean的名字取得BeanDefinition
            try {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                //取當前bean的全部依賴bean,這樣會觸發getBean的遞歸調用,直至取到一個沒有任何依賴的bean位置
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        getBean(dep);
                    }
                }
               //這裏建立Singleton bean實例,經過調用createBean方法,這裏有一個回調函數getObject,會在getSingleton中去調用ObjectFactory的createBean
               //下面會進入到createBean中去進行詳細分析
                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                                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 = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
               //這裏是建立prototype bean的地方
                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                beforePrototypeCreation(beanName);
                                try {
                                    return createBean(beanName, mbd, args);
                                }
                                finally {
                                    afterPrototypeCreation(beanName);
                                }
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // Check if required type matches the type of the actual bean instance.
          //這裏對建立出來的bean進行類型檢查,若是沒有問題,就返回這個新建立出來的bean,這個bean已經包含了依賴關係的bean
        if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
            try {
                return getTypeConverter().convertIfNecessary(bean, requiredType);
            }
            catch (TypeMismatchException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }

 這個就是依賴注入的入口,在這裏觸發了依賴注入,而依賴注入的發生是在容器中的BeanDefinition數據已經創建好的前提下進行的。

「程序=數據+算法」:前面的BeanDefinition就是數據。

怎樣依賴注入

雖然依賴注入過程不涉及複雜的算法問題,但這個過程也不簡單,由於Spring提供了許多參數配置,每個參數配置實際上表明瞭一個IoC容器的實現特性,這些特性的實現不少都須要在依賴注入的過程當中或者對Bean進行生命週期管理的過程當中來完成。IoC容器裏是經過HashMap來存儲的,但這不是IoC容器的所有。Spring IoC容器的價值體如今一系列相關的產品特性上,這些產品特性以依賴反轉模式的實現爲核心,爲用戶更好地使用依賴反轉提供便利,從而實現一個完整的IoC容器產品。

依賴注入的詳細過程

    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        //這裏判斷須要建立的bean是否能夠實例化,這個類是否能夠經過類裝載器來載入。
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

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

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            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);
        }
        //這裏是建立bean的調用
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    
    //咱們接着到doCreateBean中去看看bean是怎樣生成的:
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        //這個BeanWrapper是用來持有建立出來的bean對象的。
        BeanWrapper instanceWrapper = null;
        //若是是singleton,先把緩存中的同名bean清除。
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        //建立bean,由createBeanInstance來完成。
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
        mbd.resolvedTargetType = beanType;

        // Allow post-processors to modify the merged bean definition.
        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;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        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, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        // Initialize the bean instance.
        //這裏是對bean的初始化,依賴注入每每在這裏發生,這個exposedObject在初始化處理完成之後會返回做爲依賴注入完成後的bean
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                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<String>(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.");
                    }
                }
            }
        }

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

        return exposedObject;
    }

 

 與依賴注入關係特別密切的方法有createBeanInstance和populateBean,下面分別到這兩個方法裏看看發生了什麼。

createBeanInstance:生成bean所包含的java對象,這個對象的生成有不少不一樣的方式,能夠經過工廠方法生成,也能夠經過容器的autowire特性生成,這些生成方式都是由相關的BeanDefinition來指定的。

 

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        // Make sure bean class is actually resolved at this point.
        //確認須要建立的bean實例的類能夠實例化
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
        
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }
        //這裏使用工廠方法對bean進行實例化。
        if (mbd.getFactoryMethodName() != null)  {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // Shortcut when re-creating the same bean...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                return instantiateBean(beanName, mbd);
            }
        }

        // Need to determine the constructor...
        //使用構造函數進行實例化
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // No special handling: simply use no-arg constructor.
        //使用默認的構造函數對bean進行實例化
        return instantiateBean(beanName, mbd);
    }
    //咱們看看最多見的實例化過程instantiateBean
    protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
        //使用默認的實例化的策略對bean進行實例化,默認的實例化策略是CglibSubclassingInstantiationStrategy,也就是用cglib來對bean進行實例化。
        try {
            Object beanInstance;
            final BeanFactory parent = this;
            if (System.getSecurityManager() != null) {
                beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        return getInstantiationStrategy().instantiate(mbd, beanName, parent);
                    }
                }, getAccessControlContext());
            }
            else {
                beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
            }
            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            initBeanWrapper(bw);
            return bw;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
        }
    }

 

 在這裏用到了cglib對Bean進行實例化,cglib是一個經常使用的字節碼生成器的類庫,它提供了一系列的API來提供java的字節碼生成和轉換功能。

在實例化Bean對象生成的基礎上,咱們看看Spring是怎樣對這些對象進行處理的,也就是Bean對象生成後,怎樣把這些Bean對象的依賴關係設置好,完成整個依賴注入過程。這些依賴關係處理的依據就是已經解析獲得的BeanDefinition。

AbstractAutowireCapableBeanFactory.populateBean中的實現代碼:

    protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        //這裏取得在BeanDefinition中設置的property值,這些property來自對BeanDefinition的解析。
        PropertyValues pvs = mbd.getPropertyValues();

        if (bw == null) {
            if (!pvs.isEmpty()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }
        //開始進行依賴注入過程,先處理autowire的注入。
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            // Add property values based on autowire by name if applicable.
            //這裏是對autowire注入的處理,根據bean的名字或者type進行autowire的過程。
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }

            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }

            pvs = newPvs;
        }

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }
        //對屬性進行注入。
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
    
    //接着上面到applyPropertyValues看看具體對屬性進行解析而後注入的過程:
    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        if (pvs == null || pvs.isEmpty()) {
            return;
        }

        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        if (System.getSecurityManager() != null) {
            if (bw instanceof BeanWrapperImpl) {
                ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
            }
        }

        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // Shortcut: use the pre-converted values as-is.
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        //注意這個BeanDefinitionValueResolver對BeanDefinition的解析時在這個valueResolver中完成的。
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // Create a deep copy, resolving any references for values.
        //這裏爲解析值建立一個靠背,拷貝的數據將會被注入到bean中。
        List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                // Possibly store converted value in merged bean definition,
                // in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        //這裏是依賴注入發生的地方,會在BeanWrapperImpl中完成。
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }

 這裏經過BeanDefinitionValueResolver來對BeanDefinition進行解析,而後注入到property中。下面到BeanDefinitionValueResolver中看看解析過程的實現,以對Bean reference進行resolve的爲例子,看看整個resolve的過程:

    private Object resolveReference(Object argName, RuntimeBeanReference ref) {
        try {
            //從runtimeBeanReference取得reference的名字,這個runtimeBeanReference是在載入BeanDefinition時根據配置生成的。
            String refName = ref.getBeanName();
            refName = String.valueOf(doEvaluate(refName));
            //若是ref是在雙親IoC容器中,那就到雙親IoC容器中去取。
            if (ref.isToParent()) {
                if (this.beanFactory.getParentBeanFactory() == null) {
                    throw new BeanCreationException(
                            this.beanDefinition.getResourceDescription(), this.beanName,
                            "Can't resolve reference to bean '" + refName +
                            "' in parent factory: no parent factory available");
                }
                return this.beanFactory.getParentBeanFactory().getBean(refName);
            }
            //在當前IoC容器中去取bean,這裏會觸發一個getBean的過程,若是依賴注入沒有發生,
            //這裏會觸發相應的依賴注入的發生。
            else {
                Object bean = this.beanFactory.getBean(refName);
                this.beanFactory.registerDependentBean(refName, this.beanName);
                return bean;
            }
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    this.beanDefinition.getResourceDescription(), this.beanName,
                    "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
        }
    }

 

在Bean的建立和對象依賴注入的過程當中,須要依據BeanDefinition中的信息來遞歸地完成依賴注入。從上面能夠看到幾個遞歸的過程,這些遞歸都是以getBean爲入口的。

  • 一個是在上下文體系中查找須要的Bean和建立Bean的遞歸調用;
  • 另外一個是遞歸在依賴注入時,經過遞歸調用容器的getBean方法,獲得當前Bean的依賴Bean,同時也觸發對依賴Bean的建立和注入。在對Bean的屬性進行依賴注入時,解析的過程也是一個遞歸的過程。

這樣,根據依賴關係,一層一層的完成Bean的建立和注入,直到最後完成當前Bean的建立,有了這個頂層Bean的建立和對它的屬性依賴注入的完成,也意味着和當前Bean相關的整個依賴鏈的注入完成。

  在Bean建立和依賴注入完成之後,在IoC容器中創建一系列靠依賴關係聯繫起來的Bean,這個Bean已經不是簡單的Java對象了。這個Bean系列創建完成之後,經過IoC容器的相關接口方法,就能夠很是方便地讓上層應用使用了。

5、容器其餘相關特性的實現

5.一、lazy-init屬性和預實例化

經過設置Bean的lazy-init屬性來控制預實例化的過程,這個預實例化在初始化容器時完成Bean的依賴注入,毫無疑問,這種容器的使用方式會對容器初始化的性能有一些影響,但卻可以提升應用第一次取得Bean的性能。由於應用在第一次取得Bean時,依賴注入已經結束了,應用能夠取到現成的Bean。

再回到DefaultListableBeanFactory這個級別容器的preInstantiateSingletons。這個方法對單例Bean完成預實例化,這個預實例化的完成巧妙地委託給容器來實現。若是須要預實例化,那麼就直接在這裏採用getBean去觸發依賴注入,與正常依賴注入的觸發相比,只有觸發的時間和場合不一樣。在這裏,依賴注入發生在容器refresh的過程當中,而不像通常的依賴注是發生在IoC容器初始化完成之後,第一次向容器getBean時。

AbstractApplicationContext.refresh()

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            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.
                //這裏是對lazy-init屬性進行處理的地方。
                finishBeanFactoryInitialization(beanFactory);

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

            catch (BeansException ex) {
            //...
        }
    }

 

再接着到finishBeanFactoryInitialization(ConfigurableListableBeanFactory 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(new StringValueResolver() {
                @Override
                public String resolveStringValue(String strVal) {
                    return 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) {
            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,這個方法是有DefaultListableBeanFactory實現的。
        beanFactory.preInstantiateSingletons();
    }
    
    //在DefaultListableBeanFactory中的preInstantiateSingletons是這樣的:
    public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        //這裏就開始去getBean了,也就是去觸發bean的依賴注入。
        //若是沒有設置lazy-init,那麼這個依賴注入發生在容器初始化結束之後,第一次向容器getBean時,若是設置了lazy-init,那麼依賴注入發生在容器初始化的過程當中,
        //會對BeanDefinitionMap中全部的bean進行依賴注入, 這樣在初始化過程結束之後,當向容器getBean獲得的就是已經準備好的Bean,不須要進行依賴注入。
        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);
                }
            }
        }

        //...
    }

 

根據上面得知,能夠經過lazy-init屬性來對整個IoC容器的初始化和依賴注入過程作一些簡單的控制。

5.二、BeanPostProcessor的實現

 

BeanPostProcessor是使用IoC容器時常常遇到的一個特性,這個bean是一個後知處理器是一個監聽器,它能夠監聽容器觸發的事件。把它像IoC容器註冊之後,使得容器中管理的Bean具有了接收IoC容器事件回調的能力。
BeanPostProcessor接口有兩個方法,這些都是圍繞着Bean定義的init-method方法調用。

  • postProcessBeforeInitialization(Object bean, String beanName):爲在Bean的初始化前提供回調的入口;
  • postProcessAfterInitialization(Object bean, String beanName):爲在Bean的初始化之後提供回調的入口;

並且,這兩個回調的觸發都是和容器管理Bean的生命週期相關的。這兩個回調方法的參數都是同樣的,分別是Bean的實例化對象和Bean的名字,

postProcessBeforeInitialization是在populateBean完成以後調用的,

postProcessAfterInitialization是在populateBean方法中的initializeBean調用。

5.三、autowiring的實現

在Spring中,相對於顯示的依賴管理方式,IoC容器還提供了自動依賴裝配的方式,爲應用使用容器提供更大方便。

在自動裝配中,不須要對Bean屬性作顯示依賴關係申明,只須要配置好autowire(自動依賴裝配)屬性,IoC容器會根據這個屬性的配置,使用反射自動的查找屬性的類型或名字,而後基於屬性的類型或名字來自動匹配IoC容器中的Bean,從而自動的完成依賴注入。

相關文章
相關標籤/搜索