Spring源碼解讀, Spring啟動流程解析

知識要點:

Spring啟動流程概述

Spring啟動流程詳解

Spring啟動流程概述

Spring的IoC容器在實現(xiàn)控制反轉(zhuǎn)和依賴注入的過程中,可以劃分為兩個階段:

  • 容器啟動階段
  • Bean實例化階段

容器初始化

  • 加載配置
  • 分析配置信息
  • 將Bean信息裝配到BeanDefinition
  • 將Bean信息注冊到相應(yīng)的BeanDefinitionRegistry
  • 其他后續(xù)處理

容器實例化

  • 根據(jù)策略實例化對象
  • 裝配依賴
  • Bean初始化前處理
  • 對象初始化
  • 對象其他處理
  • 注冊回調(diào)接口

Spring啟動流程詳解

啟動流程源碼概覽

ClassPathXmlApplicationContext

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}

public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)
            throws BeansException {
    super(parent);
    Assert.notNull(paths, "Path array must not be null");
    Assert.notNull(clazz, "Class argument must not be null");
    this.configResources = new Resource[paths.length];
    for (int i = 0; i < paths.length; i++) {
        this.configResources[i] = new ClassPathResource(paths[i], clazz);
    }
    refresh();
}

AbstractApplicationContext

public void refresh() throws BeansException, IllegalStateException {
    // 方法加鎖避免多線程同時刷新Spring上下文
    synchronized (this.startupShutdownMonitor) {
        // 準備上下文刷新
        prepareRefresh();

        // 告訴子類刷新內(nèi)部的beanFactory返回新的BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 在當前上下文中準備要beanFactory
        prepareBeanFactory(beanFactory);

        try {
            // 允許在上下文子類中對beanFactory進行后置處理
            postProcessBeanFactory(beanFactory);

            // 在上下文中將BeanFactory處理器注冊為Bean
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注冊Bean處理器用于攔截Bean的創(chuàng)建
            registerBeanPostProcessors(beanFactory);

            // 在上下文中初始化國際化信息
            initMessageSource();

            // 在上下文中初始化event multicaster(事件多播器)
            initApplicationEventMulticaster();

            // 在指定的上下文子類中初始化其他指定的beans
            onRefresh();

            // 檢查并注冊事件監(jiān)聽
            registerListeners();

            // 實例化所有剩余的(非延遲初始化)單例
            finishBeanFactoryInitialization(beanFactory);

            // 最后一步:發(fā)布相應(yīng)的事件
            finishRefresh();
        }
        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                    "cancelling refresh attempt: " + ex);
            }

            // 如果出現(xiàn)異常則銷毀已創(chuàng)建的單例
            destroyBeans();

            // 重置活動標志。
            cancelRefresh(ex);

            // 將異常傳遞給調(diào)用者
            throw ex;
        }
        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

整個refresh()的代碼都是同步的繁莹,而對應(yīng)的同步對象是startupShutdownMonitor。startupShutdownMonitor只在refresh()和close()兩個方法里被用到,而它是用來同步applicationContext的刷新和銷毀仅乓。

面試題

Spring的registerShutdownHook和close有什么區(qū)別?
close()被調(diào)用時會立即關(guān)閉或者停止ApplicationContext匿又;而調(diào)用registerShutdownHook()將在稍后JVM關(guān)閉時關(guān)閉或停止ApplicationContext方灾,該方法主要通過JVM ShutdownHook來實現(xiàn)。

ShutdownHook

Java 語言提供一種 ShutdownHook(鉤子)機制碌更,當 JVM 接受到系統(tǒng)的關(guān)閉通知之后裕偿,調(diào)用 ShutdownHook 內(nèi)的方法,用以完成清理操作痛单,從而實現(xiàn)平滑退出應(yīng)用嘿棘。

第一步 刷新準備

protected void prepareRefresh() {
    // 設(shè)置啟動時間。當前毫秒數(shù)代表當前applicationContext的創(chuàng)建時間
    this.startupDate = System.currentTimeMillis();
    // 設(shè)置容器關(guān)閉標志
    this.closed.set(false);
    // 設(shè)置啟動標志
    this.active.set(true);

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

    // 初始化屬性資源
    initPropertySources();

    // 驗證所有的屬性是否都是可解析的
    getEnvironment().validateRequiredProperties();

    // ApplicationEvent初始化
    this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

第二步 獲取BeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

該方法對BeanFactory進行刷新旭绒。如果刷新前已經(jīng)存在一個BeanFactory則需要先進行關(guān)閉操作鸟妙,而后初始化一個新BeanFactory焦人。

protected final void refreshBeanFactory() throws BeansException {
    // 判斷是否已經(jīng)存在一個BeanFactory 
    if (hasBeanFactory()) {
        // 銷毀已經(jīng)存在BeanFactory中的所有Bean
        destroyBeans();
        // 關(guān)閉BeanFactory
        closeBeanFactory();
    }
    try {
        // 創(chuàng)建新的BeanFactory對象(DefaultListableBeanFactory)
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 給BeanFactory設(shè)置Id
        beanFactory.setSerializationId(getId());
        // 該方法主要對2個標志進行設(shè)置:allowBeanDefinitionOverriding和allowCircularReferences
        // allowBeanDefinitionOverriding:是否允許使用相同名稱重新注冊不同的bean(Spring默認true,SpringBoot默認false)
        // allowCircularReferences:是否允許循環(huán)依賴
        customizeBeanFactory(beanFactory);
        // 加載配置文件
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            // 新創(chuàng)建的BeanFactory賦給成員變量beanFactory
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

DefaultSingletonBeanRegistry

// 當前這個單例是否正在被銷毀
// true:表示單例已經(jīng)執(zhí)行了destroy方法重父,或者出現(xiàn)異常時執(zhí)行了destroySingleton方法
private boolean singletonsCurrentlyInDestruction = false;

// 緩存兩個Bean之間的包含關(guān)系花椭。如:一個Bean中包含了一個內(nèi)部Bean。
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<String, Set<String>>(16);

// 緩存Bean與其他依賴Bean的關(guān)系
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<String, Set<String>>(64);

// 緩存被依賴Bean與其他依賴Bean的關(guān)系
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<String, Set<String>>(64);

// 銷毀所有的Bean實例
public void destroySingletons() {
    if (logger.isDebugEnabled()) {
        logger.debug("Destroying singletons in " + this);
    }
    synchronized (this.singletonObjects) {
        // 設(shè)置銷毀標志
        this.singletonsCurrentlyInDestruction = true;
    }

    // 銷毀disposableBeans緩存中所有單例bean
    String[] disposableBeanNames;
    synchronized (this.disposableBeans) {
        disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
    }
    for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
        destroySingleton(disposableBeanNames[i]);
    }

    // 清空包含關(guān)系
    this.containedBeanMap.clear();
    // 清空依賴和被依賴關(guān)系
    this.dependentBeanMap.clear();
    this.dependenciesForBeanMap.clear();

    // 清空緩存
    clearSingletonCache();
}

加載配置

加載配置文件時序圖

AbstractXmlApplicationContext

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    // 以Resource方式加載配置
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        // 讀取配置文件
        reader.loadBeanDefinitions(configResources);
    }
    // 以String方式加載配置
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        // 讀取配置文件
        reader.loadBeanDefinitions(configLocations);
    }
}

AbstractBeanDefinitionReader

@Override
// 通過String數(shù)組參數(shù)locations加載Bean房午,并返回加載Bean的數(shù)量
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    int counter = 0;
    for (String location : locations) {
        // 加載BeanDefinintion
        counter += loadBeanDefinitions(location);
    }
    // 返回加載Bean的數(shù)量
    return counter;
}

@Override
// 通過Resource數(shù)組參數(shù)locations加載Bean矿辽,并返回加載Bean的數(shù)量
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
    Assert.notNull(resources, "Resource array must not be null");
    int counter = 0;
    for (Resource resource : resources) {
        // 加載BeanDefinintion
        counter += loadBeanDefinitions(resource);
    }
    // 返回加載Bean的數(shù)量
    return counter;
}

XmlBeanDefinitionReader

// 從配置文件中加載Bean
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);
    }

    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!");
    }
    try {
        // 將Resource資源轉(zhuǎn)化為輸入流InputStream
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            // 執(zhí)行加載Bean的過程
            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();
        }
    }
}

// 加載Bean的函數(shù)
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {
    try {
        // 加載XML文件,構(gòu)造XML Document對象
        Document doc = doLoadDocument(inputSource, resource);
        // 注冊Bean
        return registerBeanDefinitions(doc, resource);
    }
    // 拋出各種異常
    ......
}

Bean的解析與注冊

加載到解析時序圖

DefaultBeanDefinitionDocumentReader

// XML配置文件中beans元素
public static final String NESTED_BEANS_ELEMENT = "beans";
// XML配置文件中alias別名元素
public static final String ALIAS_ELEMENT = "alias";
// XML配置文件中name屬性
public static final String NAME_ATTRIBUTE = "name";
// XML配置文件中alias屬性
public static final String ALIAS_ATTRIBUTE = "alias";
// XML配置文件中import元素
public static final String IMPORT_ELEMENT = "import";
// XML配置文件中resource屬性
public static final String RESOURCE_ATTRIBUTE = "resource";
// XML配置文件中profile屬性
public static final String PROFILE_ATTRIBUTE = "profile";

protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    // 創(chuàng)建Bean解析代理工具類
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        // 解析profile屬性
        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);
    // 解析XML并執(zhí)行Bean注冊
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
}

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // root根節(jié)點是默認標簽
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        // 遍歷XML Document的每個節(jié)點
        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);
                }
            }
        }
    }
    // root根節(jié)點是自定義標簽
    else {
        delegate.parseCustomElement(root);
    }
}

// 解析XML配置文件的節(jié)點元素
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    // 如果是Import元素
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    // 如果是Alias別名元素
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    // 如果是Bean元素
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    // 如果是嵌套Bean元素(Beans)
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

Import解析
雖然每個單獨的XML配置文件都代表體系結(jié)構(gòu)中的邏輯層或模塊郭厌,但我們可以從多個XML片段中加載Bean定義袋倔。如項目中有多個Resource位置,可以使用一個或多個<import />從另外的XML文件中加載Bean定義折柠。
標簽用法示例:

<import resource="applicationDao.xml" />
<import resource="applicationService.xml" />

解析標簽的源碼:

DefaultBeanDefinitionDocumentReader

protected void importBeanDefinitionResource(Element ele) {
    String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
    if (!StringUtils.hasText(location)) {
        getReaderContext().error("Resource location must not be empty", ele);
        return;
    }

    // 解析路徑和占位符
    location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

    // 解析好的資源要放到Set里面
    Set<Resource> actualResources = new LinkedHashSet<Resource>(4);

    // 解析location是相對路徑還是絕對路徑
    boolean absoluteLocation = false;
    try {
        absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
    }
    catch (URISyntaxException ex) {
        // cannot convert to an URI, considering the location relative
        // unless it is the well-known Spring prefix "classpath*:"
    }

    // 如果是絕對路徑
    if (absoluteLocation) {
        try {
            // 直接根據(jù)路徑加載相應(yīng)的配置文件
            int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
            if (logger.isDebugEnabled()) {
                logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
            }
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error(
                "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
        }
    }
    else {
        try {
            int importCount;
            // 如果是相對路徑宾娜,則先根據(jù)路徑得到Resource
            Resource relativeResource = getReaderContext().getResource().createRelative(location);
            // 如果Resource存在
            if (relativeResource.exists()) {
                importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                actualResources.add(relativeResource);
            }
            else {
                // Resource類解析不成功,在classpath路徑中去加載扇售。如果沒有則拋出異常
                String baseLocation = getReaderContext().getResource().getURL().toString();
                importCount = getReaderContext().getReader().loadBeanDefinitions(
                    StringUtils.applyRelativePath(baseLocation, location), actualResources);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
            }
        }
        catch (IOException ex) {
            getReaderContext().error("Failed to resolve current resource location", ele, ex);
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
                                     ele, ex);
        }
    }
    Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
    getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}

Alias別名注冊

每個bean具有一個或多個標識符前塔。這些標識符在承載Bean的容器內(nèi)必須是唯一的。 Bean通常只有一個標識符缘眶,但是如果需要多個標識符嘱根,則多余的標識符可以被視為別名。
標簽用法示例:

<alias name="dataSource" alias="systemA-dataSource"/>
<alias name="dataSource" alias="systemB-dataSource"/>

在Bean定義中巷懈,可以通過使用id屬性最多指定的一個名稱该抒,同時可以通過name屬性中定義任意數(shù)量的其他名稱來為Bean提供多個名稱。但在定義Bean的地方指定所有別名可能并不能滿足需求顶燕,有時需要在其他地方為Bean定義別名凑保。
解析標簽的源碼:

SimpleAliasRegistry

// 存放別名的緩存
private final Map<String, String> aliasMap = new ConcurrentHashMap<String, String>

// 根據(jù)Bean的別名進行注冊
public void registerAlias(String name, String alias) {
    Assert.hasText(name, "'name' must not be empty");
    Assert.hasText(alias, "'alias' must not be empty");
    synchronized (this.aliasMap) {
        // 如果別名和名字相同
        if (alias.equals(name)) {
            this.aliasMap.remove(alias);
        }
        else {
            // 如果別名和名字不相同,根據(jù)別名獲取Bean名稱
            String registeredName = this.aliasMap.get(alias);
            if (registeredName != null) {
                // 如果緩存中已經(jīng)存在該別名涌攻,不需要注冊到緩存
                if (registeredName.equals(name)) {
                    // An existing alias - no need to re-register
                    return;
                }
                // 如果不允許相同的Bean使用不同的名稱則拋出異常
                if (!allowAliasOverriding()) {
                    throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                                                    name + "': It is already registered for name '" + registeredName + "'.");
                }
            }
            // 對別名進行循環(huán)檢查
            checkForAliasCircle(name, alias);
            // 把別名放入別名緩存
            this.aliasMap.put(alias, name);
        }
    }
}

// 別名循環(huán)檢查
public boolean hasAlias(String name, String alias) {
    for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
        // 獲取Bean注冊名
        String registeredName = entry.getValue();
        // 判斷name參數(shù)和Bean注冊名是否相同
        if (registeredName.equals(name)) {
            // 獲取別名
            String registeredAlias = entry.getKey();
            // 判斷別名是否相同
            // 遞歸調(diào)用hasAlias
            if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) {
                return true;
            }
        }
    }
    return false;
}

別名循環(huán)檢查:A為名稱欧引,B為A的別名,需要注冊別名<B, A>

  • 檢查B是否有別名恳谎,如果沒有則返回false
  • 如果B有別名C芝此,檢查C是否與A相同。如果相同返回true因痛,說明有別名循環(huán)婚苹。如果不相同遞歸hasAlias(C, B)方法
  • 如果C無別名,返回false鸵膏;如果C有別名D且等于A膊升,返回true。如果不相同繼續(xù)遞歸hasAlias(D, B)

Bean注冊


Spring會自動檢測構(gòu)造型類谭企,并向容器注冊相應(yīng)的BeanDefinition廓译。

DefaultBeanDefinitionDocumentReader

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 解析XML中的BeanDefinition元素
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // 注冊BeanDefinition
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                                     bdHolder.getBeanName() + "'", ele, ex);
        }
        // 發(fā)送注冊事件
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

BeanDefinitionParserDelegate

基于單一職責的緣故评肆,BeanDefinitionParserDelegate專門負責解析XML元素的工作,而DefaultBeanDefinitionDocumentReader則主要負責讀取XML配置文件的職責非区。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    // 獲取id屬性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    // 獲取name屬性
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    // 定義別名list
    List<String> aliases = new ArrayList<String>();
    if (StringUtils.hasLength(nameAttr)) {
        // 因為可以多個別名用瓜挽,所以解析成別名數(shù)組
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }

    // beanName默認為id
    String beanName = id;
    // 如果沒有beanName,那么取出別名數(shù)組中的第一個作為beanName
    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);
    }

    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    // 生成Bean名
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                        beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    // 生成Bean名
                    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;
}

// 解析Bean定義不考慮名稱或別名院仿。如果在Bean解析過程中產(chǎn)生異常秸抚,則返回null
public AbstractBeanDefinition parseBeanDefinitionElement(
    Element ele, String beanName, BeanDefinition containingBean) {

    this.parseState.push(new BeanEntry(beanName));

    String className = null;
    // 解析Bean的class屬性
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }

    try {
        String parent = null;
        // 解析parent屬性
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }
        // 為指定的類名和Parent名稱創(chuàng)建一個BeanDefinition
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);

        // 解析Bean元素的屬性并應(yīng)用于Bean
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        // 設(shè)置Bean的描述信息
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

        // 解析Bean定義的元數(shù)據(jù)信息(meta以鍵值對形式存在)
        parseMetaElements(ele, bd);
        // 解析lookup-method元素
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        // 解析replaced-method元素
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

        // 解析構(gòu)造函數(shù)參數(shù)
        parseConstructorArgElements(ele, bd);
        // 解析property元素
        parsePropertyElements(ele, bd);
        // 解析qualifier元素
        parseQualifierElements(ele, bd);

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

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

BeanDefinitionReaderUtils

該類的主要職責用于生產(chǎn)新的BeanDefiniti實例速和,給Bean生成一個名稱及調(diào)用BeanDefinitionRegistry進行Bean的注冊歹垫。

public static String generateBeanName(
    BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
    throws BeanDefinitionStoreException {

    String generatedBeanName = definition.getBeanClassName();
    if (generatedBeanName == null) {
        // 如果有父類,名稱為:definition.getParentName() + “$child”
        if (definition.getParentName() != null) {
            generatedBeanName = definition.getParentName() + "$child";
        }
        // 如果有指定的工廠類颠放,名稱為:definition.getFactoryBeanName() + “$created”
        else if (definition.getFactoryBeanName() != null) {
            generatedBeanName = definition.getFactoryBeanName() + "$created";
        }
    }
    if (!StringUtils.hasText(generatedBeanName)) {
        throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
                                               "'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
    }

    String id = generatedBeanName;
    if (isInnerBean) {
        // 如果是innerBean排惨,名稱為
        id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
    }
    else {
        // 如果不是InnerBean則為頂層Bean,使用簡單的類名碰凶。計數(shù)器加1
        int counter = -1;
        while (counter == -1 || registry.containsBeanDefinition(id)) {
            counter++;
            id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
        }
    }
    return id;
}
  • parent
    Bean定義可以包含許多配置信息暮芭,包括容器相關(guān)的信息(比如初始化方法,靜態(tài)工廠方法等等)以及構(gòu)造函數(shù)參數(shù)和屬性的值欲低。子Bean可以定義從父Bean定義中繼承配置數(shù)據(jù)辕宏,而后它可以根據(jù)需要覆蓋某些值,或添加其他值砾莱。使用父子Bean可以節(jié)省很多輸入工作瑞筐。
  • lookup-method
    lookup-method注入是容器重寫B(tài)ean上的方法的一種能力,它可以在容器中根據(jù)一個Bean的名字返回查找結(jié)果腊瑟。lookup-method通常涉及Prototype Bean聚假。Spring框架通過使用CGLIB來覆蓋該方法的子類以實現(xiàn)lookup-method的注入。該功能可用于在一些可插拔的功能上解除依賴闰非。
  • replace-method
    用于在運行時調(diào)用使用新的方法替換原有的方法膘格,還能動態(tài)的改變原有方法的邏輯。

DefaultListableBeanFactory

// 手動注冊的單例名稱列表
private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16);

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屬性中的methodOverrides校驗
            // 校驗methodOverrides是否與工廠方法并存或者methodOverrides對應(yīng)的方法根本不存在
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Validation of bean definition failed", ex);
        }
    }

    // 從緩存中根據(jù)beanName獲取BeanDefinition
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        // 如果BeanDefinition存在并且不允許同名覆蓋财松,則拋出異常
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                                                   "': There is already [" + existingDefinition + "] bound.");
        }
        // Bean的角色檢查
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (logger.isWarnEnabled()) {
                logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
            }
        }
        // 如果名字相同瘪贱,但是BeanDefinition不同打印覆蓋日志
        else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isInfoEnabled()) {
                logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
            }
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                             "' with an equivalent definition: replacing [" + existingDefinition +
                             "] with [" + beanDefinition + "]");
            }
        }
        // 在緩存中注冊Bean
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        // 檢查工廠的Bean創(chuàng)建階段是否已經(jīng)開始
        if (hasBeanCreationStarted()) {
            // 進入創(chuàng)建階段,此時無法再修改啟動時集合元素(為了穩(wěn)定迭代)
            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;
                // beanName在manualSingletonNames中辆毡,說明是手動注冊
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
            // 工廠還未到創(chuàng)建階段菜秦,仍然在注冊階段
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    // 待注冊的Bean的已經(jīng)在beanDefinitionMap緩存中存在,或者已經(jīng)存在于單例Bean緩存中
    if (existingDefinition != null || containsSingleton(beanName)) {
        // 重置給定Bean的所有BeanDefinition緩存胚迫,包括從其派生的Bean的緩存
        resetBeanDefinition(beanName);
    }
}

AbstractBeanFactory

// 保存在至少被創(chuàng)建過一次的beanName
// 如果這個集合中存在beanName喷户,那么說明已經(jīng)進入了Bean創(chuàng)建階段
private final Set<String> alreadyCreated =
            Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256))
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市访锻,隨后出現(xiàn)的幾起案子褪尝,更是在濱河造成了極大的恐慌闹获,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件河哑,死亡現(xiàn)場離奇詭異避诽,居然都是意外死亡,警方通過查閱死者的電腦和手機璃谨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門沙庐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人佳吞,你說我怎么就攤上這事拱雏。” “怎么了底扳?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵铸抑,是天一觀的道長。 經(jīng)常有香客問我衷模,道長鹊汛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任阱冶,我火速辦了婚禮刁憋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘木蹬。我一直安慰自己至耻,他們只是感情好,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布届囚。 她就那樣靜靜地躺著有梆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪意系。 梳的紋絲不亂的頭發(fā)上泥耀,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音蛔添,去河邊找鬼痰催。 笑死,一個胖子當著我的面吹牛迎瞧,可吹牛的內(nèi)容都是我干的夸溶。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼凶硅,長吁一口氣:“原來是場噩夢啊……” “哼缝裁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起足绅,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤捷绑,失蹤者是張志新(化名)和其女友劉穎韩脑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粹污,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡段多,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了壮吩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片进苍。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鸭叙,靈堂內(nèi)的尸體忽然破棺而出觉啊,到底是詐尸還是另有隱情,我是刑警寧澤递雀,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布柄延,位于F島的核電站,受9級特大地震影響缀程,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜市俊,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一杨凑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摆昧,春花似錦撩满、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至忌锯,卻和暖如春伪嫁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背偶垮。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工张咳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人似舵。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓脚猾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親砚哗。 傳聞我的和親對象是個殘疾皇子龙助,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容