天天看點

Spring系列(五) 容器初始化過程源碼

IoC/DI 的概念

容器是Spring的核心之一(另一個核心是AOP). 有了容器, IOC才可能實作.

  • 什麼使IoC? IoC就是将類自身管理的與其由依賴關系的對象的建立/關聯和管理交予容器實作, 容器按照配置(比如xml檔案)來組織應用對象的建立和關聯.
  • 什麼使DI? DI是IoC的實作方式, 由容器在程式初始化的時候将類的依賴對象注入進去.
  • IoC和DI的關系? IoC(Inversion of Control)是一種設計原則, 可以減少代碼的耦合度, DI(Dependency Injection)是IOC的具體實作方式, 還有其他的實作方式如 DL(Dependency Lookup).

Spring 容器

ClassPathXmlApplicationContext

類應該都比較熟悉, 從熟悉的事物開始尋找線索.

下載下傳Spring源碼後用idea打開, 找到類

ClassPathXmlApplicationContext

, idea可以使用

ctrl+N

輸入類名搜尋, 打開源檔案, 按

ctrl+Alt+U

可以生成類圖.

Spring系列(五) 容器初始化過程源碼

BeanFactory

ResourceLoader

是兩個頂層接口.

BeanFactory

是Bean的工廠,定義了IoC基本的功能.

ResourceLoader

是資源加載的政策接口,定義了加載資源的基本規範,

ApplicationContext

需要此接口的功能.

BeanFactory

提供了容器最基本的功能, 其中定義的方法會頻繁使用, 接口定義如下:

public interface BeanFactory {
    // 一個标記, 帶有此标記開頭的類不是bean, 而是工廠本身
    String FACTORY_BEAN_PREFIX = "&";
    // 下面幾個方法是各種擷取bean的方式
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    // 判斷bean是否存在
    boolean containsBean(String name);
    // bean作用域是否單例
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    // bean作用域是否原型
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    // bean是否與給定解析類型比對
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    // 擷取bean類型
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    //擷取bean别名數組
    String[] getAliases(String name);

}           

ApplicationContext

擴充了

BeanFactory

的功能, 除了作為工廠外, 它還提供了消息國際化(

MessageSource

), 擷取環境bean(

EnvironmentCapable

), 容器消息釋出(

ApplicationEventPublisher

)等功能. 因為它包含了容器以外的這些功能, 是以對了解容器來說多少會産生幹擾. 事實上, 檢視

BeanFactory

的子類(在類圖上選中類,或者在源代碼視圖中按

Ctrl+Alt+B

)能從它的實作中找到

DefaultListableBeanFactory

, 從名稱上二者在繼承該關系上應該比較近, 功能也比較純粹, 沒有類似ApplicationContext的其他幹擾.

DefaultListableBeanFactory

類是最基本的容器實作類, 它的繼承關系如下圖. 作為bean的工廠, 它的職責就是生産bean, 基本功能正是頂級接口

BeanFactory

定義的那些方法. 它上級的接口擴充了自動裝配的能力(

AutowireCapableBeanFactory

), 注冊和擷取等操作

BeanDefinition

執行個體的能力(

BeanDefinitionRegistry

).

Spring系列(五) 容器初始化過程源碼

BeanDefinition

BeanDefinition 用來抽象bean定義在spring中的抽象, 最終spring将外部配置的bean轉化為

BeanDefinition

的執行個體存儲.

Spring系列(五) 容器初始化過程源碼

容器初始化過程

容器初始化過程分為三步, 資源Resource定位, 解析加載, 注冊.

DefaultListableBeanFactory

是工廠, 繼承它的子類隻有一個

XmlBeanFactory

, 它被标注為

@Deprecated

.是以不應該在應用中使用該類, 但它可以作為了解源碼的入口. 它有個

XmlBeanDefinitionReader

的私有變量直接new初始化, 參數this将工廠執行個體傳給這個對象, 這樣它就有了工廠的引用, 友善内部處理.

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

大概串一下初始化的執行流程:

  1. 獲得一個

    Resource

    執行個體resource, 其實就是xml檔案生成的輸入流
  2. 執行個體化

    DefaultListableBeanFactory

    工廠beanFactory, 将resource作為構造參數傳入
  3. beanFactory執行個體化, 生成

    XmlBeanDefinitionReader

    的執行個體reader, 并将beanFactory的引用傳遞給他
  4. 在beanFactory構造函數中調用reader的方法加載resource, 解析生成一系列

    BeanDefinition

    的執行個體, 因為readere有工廠的執行個體, 是以這些執行個體可以注冊到工廠中

加載XML Bean的關鍵代碼

下面按照調用關系跟蹤代碼, 忽略其他的xml元素, 最終目标是找到加載注冊bean的機制.

XmlBeanDefinitionReader

--> loadBeanDefinitions

--> doLoadBeanDefinitions

--> registerBeanDefinitions

DefaultBeanDefinitionDocumentReader: BeanDefinitionDocumentReader

--> doRegisterBeanDefinitions

--> parseBeanDefinitions

--> parseDefaultElement / processBeanDefinition

BeanDefinitionParserDelegate

--> parseBeanDefinitionElement

BeanDefinitionReaderUtils

--> registerBeanDefinition

DetaultListableBeanFactory

一.

XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)

生成InputSource對象(用來初始化XML Dom對象)

InputStream inputStream = encodedResource.getResource().getInputStream();
try {
    // 生成執行個體, 後面用來加載dom
    InputSource inputSource = new InputSource(inputStream);
    if (encodedResource.getEncoding() != null) {
        inputSource.setEncoding(encodedResource.getEncoding());
    }
    // 生成InputSource後,調用這個方法
    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
    inputStream.close();
}           

二.

XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)

加載生成Xml Document對象

// 生成doc執行個體
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);           

三.

XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource)

// 生成BeanDefinitionDocumentReader的執行個體, 預設實作為生成DefaultBeanDefinitionDocumentReader類的執行個體, 通過BeanUtil工具的執行個體化方法生成
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 傳入doc和資源的上下文對象, 注冊bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));           

四.

registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

BeanDefinitionDocumentReader

是接口, 實作類為

DefaultBeanDefinitionDocumentReader

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    // 擷取根節點
    Element root = doc.getDocumentElement();
    // 從根節點開始, 調用的這個方法會遞歸子節點
    doRegisterBeanDefinitions(root);
}           

五.

doRegisterBeanDefinitions(Element root)

類為

DefaultBeanDefinitionDocumentReader

protected void doRegisterBeanDefinitions(Element root) {
    //任何嵌套的<beans>元素都将導緻此方法的遞歸。為了正确傳播和保留<beans> default- *屬性,請跟蹤目前(父)委托,該委托可以為null。建立新的(子)委托,引用父項以進行回退,然後最終将this.delegate重置為其原始(父)引用。此行為模拟了一堆代理,而實際上并不需要一個代理。
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        // 下面這一塊代碼主要是做profile檢查, 沒有啟用profile的bean不加載, 将直接return
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                            "] not matching: " + getReaderContext().getResource());
                }
                return;
            }
        }
    }

    preProcessXml(root);
    // 具體解析的方法, pre和post的在這個類中為空方法
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
}           

六.

parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

DefaultBeanDefinitionDocumentReader

/**
* 解析文檔中的根節點
* "import", "alias", "bean".
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 是根節點,就擷取子節點, 周遊,如果是根"import", "alias", "bean", 就調用parseDefaultElement, 否則parseCustomElement
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    parseDefaultElement(ele, delegate);
                }
                else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}           

七.

parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)

DefaultBeanDefinitionDocumentReader

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            // 解析"import"元素, 這個方法會定位import的資源位置并重複第一步開始的步驟
            importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            // 别名"alias"注冊
            processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            // 前方高能... 處理bean元素
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // 遞歸"beans"
            doRegisterBeanDefinitions(ele);
        }
    }           

八.

processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

DefaultBeanDefinitionDocumentReader

/**
*  處理bean元素的定義, 并且注冊
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 擷取bean的包裝對象,代碼見第九步
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // 注冊最終的bean裝飾對象
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}           

九.

parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)

BeanDefinitionParserDelegate

關注兩個執行個體化過程,一個是

BeanDefinition

, 一個是其裝飾對象

BeanDefinitionHolder

的執行個體

/**
* 解析bean元素, 可能會傳回null, 如果有錯誤則報告給
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    List<String> aliases = new ArrayList<>();
    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);
    }
    // 執行個體化一個 BeanDefination 執行個體
    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);
                    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;
}           

十.

registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

是類的靜态方法

BeanDefinitionReaderUtils

;給registry對象調用

// 注冊bean的最終方法
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {

    // 使用首要名稱注冊bean
    String beanName = definitionHolder.getBeanName();
    // 注冊bean, 具體實作在類DetaultListableBeanFactory中
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // 注冊bean的别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}           

十一.

registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

在類

DetaultListableBeanFactory

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
    ....

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        ....
        // 存到map裡面
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    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<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<>(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 (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}           

到目前為止, bean就注冊到工廠裡面去了, 實際上工廠裡面儲存了BeanDefinition的一個映射Map, 這樣有助于Spring做一些驗證, 當擷取bean的時候也可以友善實作懶加載.