源碼成神之路:Spring Framework源代碼解析之IOC容器(二)

在上文(Spring Framework源代碼解析之IOC容器(一))中,我們簡單瞭解了Spring的IOC特性,但對Spring相關源碼沒有做詳細的分析,本文將對支持IOC特性的重要代碼進行分析,有不對的地方請指正。

水桶的標準——BeanFactory

我們說Spring中包含了IOC的容器,倒不如說它包含了一系列容器的集合,因為IOC容器不只一個,像ConfigurableBeanFactory、XmlBeanFactory、ApplicationContext都是IOC容器。它們就像一個個水桶,都能夠裝水(放置Java Bean),但外觀、樣式、使用場景可能有所不同,使用者可以根據自己的需求使用不同的“水桶”。但不管是哪個“水桶”,它們都會一些基本的功能,比如裝水。所以我們發現這些容器它們都實現了一個相同的接口—— BeanFactory。BeanFactory定義了這些容器基本的功能,比如getBean、containsBean、isSingleton等等。

getBean是BeanFactory最重要一個方法,作用是從IOC容器中取得指定的Bean,它還有一個重載方法可以指定類型來獲取Bean。

containsBean是用來判斷容器中是否包含指定的Bean。

isSingleton是用來判斷指定的Bean是否是單例類型的Bean。

……

這些方法指定了每一個容器都必須實現的一些功能,也是支持IOC容器的最基本功能。

BeanFactory源碼清單:

<code>public interface BeanFactory {
 

    String FACTORY_BEAN_PREFIX = "&";
 
    Object getBean(String name) throws BeansException;
 
     T getBean(String name, Class requiredType) throws BeansException;
     
     T getBean(Class requiredType) throws BeansException;
 
    Object getBean(String name, Object... args) throws BeansException;
 
    boolean containsBean(String name);
 
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
 
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
 
    boolean isTypeMatch(String name, Class> targetType) throws NoSuchBeanDefinitionException;
 
    Class> getType(String name) throws NoSuchBeanDefinitionException;
 
    String[] getAliases(String name);
 
}/<code>

說完水桶的標準,我們眼前出現各式各樣的“水桶”,但有些水桶功能過於複雜,有些又實用性不好,我們得選一個經濟實用的水桶來研究,XmlBeanFactory就是這樣的水桶。

屌絲版水桶——XmlBeanFactory

之所以稱為屌絲版,是因為XmlBeanFactory只提供了最基本的IOC容器的功能,從名字來看,這個IOC容器可以讀取XML文件定義的BeanDefinition(XML文件中對bean的描述)。什麼是BeanDefinition呢,我們說IOC容器是用來裝對象的,而具體描述裝了哪些對象,對象之間的依賴關係又是什麼?則是用BeanDefinition來描述,可以結合XML文件來理解它。

我們看一下XmlBeanFactory的繼承關係:

源碼成神之路:Spring Framework源代碼解析之IOC容器(二)

BeanFactory不用說了,AutowireCapableBeanFactory、AbstractAutowireCapableBeanFactory最主要的功能就是實現bean創建方法createBean()。

<code>T createBean(Class beanClass) throws BeansException;/<code>

接下來是DefaultListableBeanFactory,它很重要,很多容器都會繼承它。從名字上看,它應該是一個默認的功能完備的BeanFactory,我們可以把它當做為水桶的半成品,功能健全,但使用的時候還需要包裝。XmlBeanFactory就是包裝它實現的一個基本容器。XmlBeanFactory除了包含DefaultListableBeanFactory的功能外,最重要的它支持以XML目錄文件方式定義BeanDefinition。

XmlBeanFactory怎麼讀取Xml文件?

XmlBeanFactory源文件中,並看到讀取Xml文件的具體實現,可見讀取Xml文件並不是由XmlBeanFactory直接完成的。

XmlBeanFactory.java

<code>public class XmlBeanFactory extends DefaultListableBeanFactory {
 
    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
 
 
    /**
     * Create a new XmlBeanFactory with the given resource,
     * which must be parsable using DOM.
     * @param resource XML resource to load bean definitions from
     * @throws BeansException in case of loading or parsing errors
     */
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }
 
    /**
     * Create a new XmlBeanFactory with the given input stream,

     * which must be parsable using DOM.
     * @param resource XML resource to load bean definitions from
     * @param parentBeanFactory parent bean factory
     * @throws BeansException in case of loading or parsing errors
     */
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }
 
}/<code>

我們注意到XmlBeanFactory.java開始實例化了一個XmlBeanDefinitionReader對象reader。實際上Xml文件的處理就是由這個reader來完成的。接著往下看XmlBeanFactory構造函數中需要一個Resource對象,它包含了BeanDefinition的信息,也就是在Xml配置文件當中的定義的Bean信息。Spring需要把它封裝成Resource對象進行處理。

從XML文件讀取Bean信息保存在Resource對象當中的方法:

<code>ClassPathResource resource = new ClassPathResource(
            "application-context.xml");/<code>

有了Resource對象,reader執行loadBeanDefinitions方法。

<code>this.reader.loadBeanDefinitions(resource);/<code>

就是這個方法從Resource載入BeanDefinition到讀取器(XmlBeanDefinitionReader)中。

我們再來梳理一下XmlBeanFactory的整個流程:

<code>ClassPathResource resource = new ClassPathResource(
            "application-context.xml");
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    reader.loadBeanDefinitions(resource);/<code>

1)根據Xml配置文件創建Resource資源對象,該對象中包含了BeanDefinition的信息。

2)創建DefaultListableBeanFactory。

3)創建XmlBeanDefinitionReader讀取器,用於載入BeanDefinition。之所以需要BeanFactory作為參數,是因為會將讀取的信息回調配置給factory。

4)XmlBeanDefinitionReader執行載入BeanDefinition的方法,最後會完成Bean的載入和註冊。完成後Bean就成功的放置到IOC容器當中,以後我們就可以從中取得Bean來使用。

水桶中的高帥富——ApplicationContext

如果說XmlBeanFactory是容器中的屌絲,ApplicationContext應該算容器中的高帥富,瀏覽一下ApplicationContext。

ApplicationContext.java

<code>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 null if none
     */
    String getId();
 
    /**
     * Return a friendly name for this context.
     * @return a display name for this context (never null)
    */
    String getDisplayName();
 
    /**
     * Return the timestamp when this context was first loaded.
     * @return the timestamp (ms) when this context was first loaded
     */
    long getStartupDate();
 
    /**
     * Return the parent context, or null if there is no parent

     * and this is the root of the context hierarchy.
     * @return the parent context, or null if there is no parent
     */
    ApplicationContext getParent();
 
    /**
     * Expose AutowireCapableBeanFactory functionality for this context.
     * This is not typically used by application code, except for the purpose
     * of initializing bean instances that live outside the application context,
     * applying the Spring bean lifecycle (fully or partly) to them.
     * Alternatively, the internal BeanFactory exposed by the
     * {@link ConfigurableApplicationContext} interface offers access to the
     * AutowireCapableBeanFactory interface too. The present method mainly
     * serves as convenient, specific facility on the ApplicationContext
     * interface itself.
     * @return the AutowireCapableBeanFactory for this context
     * @throws IllegalStateException if the context does not support
     * the AutowireCapableBeanFactory interface or does not hold an autowire-capable
     * bean factory yet (usually if refresh() has never been called)
     * @see ConfigurableApplicationContext#refresh()
     * @see ConfigurableApplicationContext#getBeanFactory()
     */
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
 
}/<code>

ApplicationContext是一個接口,它定義了一組實現高級IOC容器的標準,看看它的配置:

<code>public interface ApplicationContext extends
 
EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {……}/<code>

比較XmlBeanFactory只繼承DefaultListableBeanFactory,它顯得豪華得多。可以看到它繼承MessageSource,這樣他支持不同的信息源,國際化實現也依賴它。它還繼承ApplicationEventPublisher,這讓它支持事件機制,可以利用它根據生命週期做更多的事……

總之ApplicationContext是一個高級形式的IOC容器,再以後的學習中它的出場率會很高,我們慢慢了解它。

小結

本問介紹了與IOC容器相關的基礎類,主要為後面學習依賴注入做鋪墊,下文將重點介紹依賴注入的詳細實現。


分享到:


相關文章: