Spring源码之IoC容器初始化过程,以FileSystemXmlApplicationContext容器为例

学习记录,以供以后查阅!参考书籍《Spring技术内幕》。

本篇文章以Spring 5.2.15.RELEASE版本的FileSystemXmlApplicationContext容器为例进行梳理。

1、IoC容器初始化过程概述

在这里插入图片描述

IOC容器的初始化过程,简单来说是由refresh方法完成初始化工作。
具体来讲包括如下三个步骤:
1、Resource资源的定位。(简单的讲就是读取xml文件中的bean配置,获取数据流的过程)
2、BeanDefinition的载入和解析。(简单讲就是把xml中bean的定义,转化为IOC容器识别的数据格式,这个格式就是BeanDefinition)
3、向IOC容器注册BeanDefinition的过程。(简单的讲就是把这些BeanDefinition,转换为对象注册进IOC容器的过程)

1.1 FileSystemXmlApplicationContext 继承关系图

在这里插入图片描述

1.2 FileSystemXmlApplicationContext 源码

从源码中可以看到容器的初始化工作是通过refresh()方法来启动的

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
    public FileSystemXmlApplicationContext() {
    }

    public FileSystemXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }
	// configLocation包含的是BeanDfinition所在的文件路径
    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
    }

    public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, (ApplicationContext)null);
    }

    public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }

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

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        // 保存BeanDfinition所在的文件路径
        this.setConfigLocations(configLocations);
        if (refresh) {
        	// 启动容器初始化
            this.refresh();
        }

    }

    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }

        return new FileSystemResource(path);
    }
}

1.3 refresh()方法流程图

在这里插入图片描述

1.4 refresh()方法源码

refresh()在FileSystemXmlApplicationContext类的父类AbstractApplicationContext中实现

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

1.5 BeanFactory容器的创建

BeanFactory的创建过程如下:
1、refresh()方法调用this.obtainFreshBeanFactory()方法。
2、obtainFreshBeanFactory()调用了refreshBeanFactory()方法。
3、refreshBeanFactory()方法创建一个DefaultListableBeanFactory。
在这里插入图片描述

1.6 refreshBeanFactory()流程

如果容器存在,则销毁和关闭
创建IOC容器DefaultListableBeanFactory
启动对BeanDefinition的载入

    protected final void refreshBeanFactory() throws BeansException {
    	// 如果容器存在,则销毁和关闭
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
        	// 创建IOC容器DefaultListableBeanFactory 
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            // 启动对BeanDefinition的载入
            this.loadBeanDefinitions(beanFactory);
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

1.7 创建DefaultListableBeanFactory容器

    protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory(this.getInternalParentBeanFactory());
    }

2、Resource资源的定位

2.1 创建XmlBeanDefinitionReader

1、初始化读取器XmlBeanDefinitionReader,并通过回调设置到BeanFactory中。
2、通过XmlBeanDefinitionReader加载资源。

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    	// 创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        // 这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配置
        // ResourceLoader,因为defaultResourceLoader是父类,所以this可以直接被使用
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        
        this.initBeanDefinitionReader(beanDefinitionReader);
        // 启动Bean定义信息的载入过程
        this.loadBeanDefinitions(beanDefinitionReader);
    }

2.2 获得资源合集,通过XmlBeanDefinitionReader读取资源

AbstractXmlApplicationContext中loadBeanDefinitions实现
首先,获得Resource/String定位资源合集。
然后,调用XmlBeanDefinitionReader的loadBeanDefinitions读取资源。

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    	// 以Resource的方式获得配置文件的资源位置
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
        	// 调用XmlBeanDefinitionReader来读取资源进行载入
            reader.loadBeanDefinitions(configResources);
        }
		// 以String的形式获得配置文件的位置
        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
        	// 调用XmlBeanDefinitionReader来读取资源进行载入
            reader.loadBeanDefinitions(configLocations);
        }

    }

2.3 载入以Resource的方式获得的资源

AbstractBeanDefinitionReader中loadBeanDefinitions实现

    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
    	// 如果Resource为空,则停止BeanDefinition的载入
    	// 然后启动载入BeanDefinition的过程,
    	// 这个过程遍历整个Resource集合所包含的BeanDefinition信息
        Assert.notNull(resources, "Resource array must not be null");
        int count = 0;
        Resource[] var3 = resources;
        int var4 = resources.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Resource resource = var3[var5];
            count += this.loadBeanDefinitions((Resource)resource);
        }

        return count;
    }

3、BeanDefinition的载入和解析

XmlBeanDefinitionReader中 loadBeanDefinitions(Resource resource)方法的实现。
1、获取文件输入流InputStream
2、获得XML读取流InputSource
3、取得XML文件的Document对象
4、调用registerBeanDefinitions方法解析XML

	// Resource封装了对XML文件的I/O操作
	// Reader读取器可以打开I/O操作得到XML的文件对象
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return this.loadBeanDefinitions(new EncodedResource(resource));
    }

	// 载入XML形式的BeanDefinition
    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (this.logger.isInfoEnabled()) {
            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }

        if (!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
            	// 这里得到XML文件,并得到IO的InputSource准备进行读取
                InputStream inputStream = encodedResource.getResource().getInputStream();

				
                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }

                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                    inputStream.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if (((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var5;
        }
    }
	// 具体的读取过程如下
	// 这是从特定的XML文件中实际载入BeanDefinition的地方
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
        	// 这里取得XML文件的Document对象
            Document doc = this.doLoadDocument(inputSource, resource);
            // 这里启动的是对BeanDefinition解析的详细过程,这个解析会用到Spring的Bean配置规则
            return this.registerBeanDefinitions(doc, resource);
        } catch (BeanDefinitionStoreException var4) {
            throw var4;
        } catch (SAXParseException var5) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
        } catch (SAXException var6) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
        } catch (ParserConfigurationException var7) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
        } catch (IOException var8) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
        } catch (Throwable var9) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
        }
    }

3.1 Spring的BeanDefinition是怎样按照Spring的Bean语义要求进行解析并转化为容器内部数据结构的

具体过程是由BeanDefinitionDocumentReader来完成的,这个registerBeanDefinition还对载入的Bean数量进行了统计。如下所示。

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    	// 这里得到BeanDefinitionDocumentReader来对XML的BeanDefinition进行解析
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        // 具体的解析过程在这个registerBeanDefinitions中完成
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

3.2 BeanDefinitionDocumentReader的创建

    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
        return (BeanDefinitionDocumentReader)BeanUtils.instantiateClass(this.documentReaderClass);
    }

得到documentReader以后,为具体的Spring Bean的解析过程准备好了数据
具体的解析过程是由processBeanDefinition方法完成的,调用方法栈如下

在这里插入图片描述

3.3 调用processBeanDefinition方法解析BeanDefinition

processBeanDefinition是处理BeanDefinition的地方
具体的处理委托给BeanDefinitionParserDelegate来完成
ele对应在Spring BeanDefinition中定义的XML元素

BeanDefinitionHolder是BeanDefinition对象的封装类
封装了BeanDefinition,Bean的名字和别名
用它来完成向IOC容器注册
得到这个BeanDefinitionHolder就意味着BeanDefinition
是通过BeanDefinitionParserDelegate对XML元素的信息
按照Spring的Bean规则进行解析得到的

最后把BeanDefinitionHolder注册到IOC容器
注册完成,发送消息

	// 这里是处理BeanDefinition的地方,
	// 具体的处理委托给BeanDefinitionParserDelegate来完成
	// ele对应在Spring BeanDefinition中定义的XML元素
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    	// BeanDefinitionHolder是BeanDefinition对象的封装类
    	// 封装了BeanDefinition,Bean的名字和别名
    	// 用它来完成向IOC容器注册
    	// 得到这个BeanDefinitionHolder就意味着BeanDefinition
    	// 是通过BeanDefinitionParserDelegate对XML元素的信息
    	// 按照Spring的Bean规则进行解析得到的
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
            // 这里是向IOC容器注册解析得到BeanDefinition的地方
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }

			// 在BeanDefinition向IOC容器注册完以后,发送消息 
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

3.4 详细的XML解析过程

BeanDefinitionParserDelegate类中包含了对各种Spring Bean定义规则的处理

    @Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
        return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
    }
    @Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    	// 这里取得在<bean>元素中定义的id、name、aliase属性的值
        String id = ele.getAttribute("id");
        String nameAttr = ele.getAttribute("name");
        List<String> aliases = new ArrayList();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(nameArr));
        }

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

        if (containingBean == null) {
            this.checkNameUniqueness(beanName, aliases, ele);
        }
        // 这个方法会引发对Bean元素的详细解析

        AbstractBeanDefinition beanDefinition = this.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 (this.logger.isTraceEnabled()) {
                        this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }

3.5 具体生成BeanDefinition的地方

对BeanDefinition元素处理的代码
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);

    @Nullable
    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        // 这里只读取定义的<bean>中设置的class名字,然后载入到BeanDefinition中去
        // 只是做个记录,并不涉及对象的实例化过程
        // 对象的实例化实际上是在依赖注入时完成的
        String className = null;
        if (ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }

        String parent = null;
        if (ele.hasAttribute("parent")) {
            parent = ele.getAttribute("parent");
        }

        try {
        	// 这里生成需要的BeanDefinition对象,为Bean定义信息的载入做准备
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            // 这里对当前的Bean元素进行属性解析,并设置description的信息
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            // 从名字可以清楚的看到,这里是对各种<bean>元素的信息进行解析的地方
            this.parseMetaElements(ele, bd);
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            // 解析<bean>的构造函数设置
            this.parseConstructorArgElements(ele, bd);
            // 解析<bean>的property设置
            this.parsePropertyElements(ele, bd);
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        // 下面这些异常是在配置Bean出现问题时经常会看到的,原来是在这里抛出的,这些检查是在
        // createBeanDefinition时进行的,会检查Bean的class设置是否正确,比如这个类是否能找到
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

        return null;
    }

3.6 举一个对property进行解析的例子

举一个对property进行解析的例子,来完成对整个BeanDefinition载入过程的分析,还是在类BeanDefinitionParserDelegate的代码中,一层一层地对BeanDefinition中的定义进行解析,比如从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会被封装成PropertyValue对象并设置到BeanDefinition对象中去。

这里对指定Bean元素的property子元素集合进行解析
遍历所有Bean元素下定义的property元素
在判断是property元素后,对该元素进行解析

	// 这里对指定Bean元素的property子元素集合进行解析
    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
        NodeList nl = beanEle.getChildNodes();
		// 遍历所有Bean元素下定义的property元素
        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if (this.isCandidateElement(node) && this.nodeNameEquals(node, "property")) {
            	// 在判断是property元素后,对该元素进行解析
                this.parsePropertyElement((Element)node, bd);
            }
        }

    }

3.7 解析property元素

    public void parsePropertyElement(Element ele, BeanDefinition bd) {
    	// 这里取得property的名字
        String propertyName = ele.getAttribute("name");
        if (!StringUtils.hasLength(propertyName)) {
            this.error("Tag 'property' must have a 'name' attribute", ele);
        } else {
            this.parseState.push(new PropertyEntry(propertyName));

            try {
            	// 如果同一个Bean中已经有同名的property存在,则不进行解析,直接返回。
            	// 也就是说,如果同一个Bean中有同名的property设置,那么只有第一个起作用
                if (bd.getPropertyValues().contains(propertyName)) {
                    this.error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
                    return;
                }
				// 这里是解析property值的地方,返回的对象对应对Bean定义的property属性设置的解析结果。
				// 这个解析结果会封装到PropertyValue对象中,然后设置到BeanDefinitionHolder中去
                Object val = this.parsePropertyValue(ele, bd, propertyName);
                PropertyValue pv = new PropertyValue(propertyName, val);
                this.parseMetaElements(ele, pv);
                pv.setSource(this.extractSource(ele));
                bd.getPropertyValues().addPropertyValue(pv);
            } finally {
                this.parseState.pop();
            }

        }
    }

3.8 获取property元素的值

	// 这里取得property元素的值,也许是一个list或其他
    @Nullable
    public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
        String elementName = propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
        NodeList nl = ele.getChildNodes();
        Element subElement = null;

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if (node instanceof Element && !this.nodeNameEquals(node, "description") && !this.nodeNameEquals(node, "meta")) {
                if (subElement != null) {
                    this.error(elementName + " must not contain more than one sub-element", ele);
                } else {
                    subElement = (Element)node;
                }
            }
        }
		// 这里判断property的属性,是ref海水value,不允许同时是ref和value
        boolean hasRefAttribute = ele.hasAttribute("ref");
        boolean hasValueAttribute = ele.hasAttribute("value");
        if (hasRefAttribute && hasValueAttribute || (hasRefAttribute || hasValueAttribute) && subElement != null) {
            this.error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
        }
		// 如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息
        if (hasRefAttribute) {
            String refName = ele.getAttribute("ref");
            if (!StringUtils.hasText(refName)) {
                this.error(elementName + " contains empty 'ref' attribute", ele);
            }
			
            RuntimeBeanReference ref = new RuntimeBeanReference(refName);
            ref.setSource(this.extractSource(ele));
            return ref;
        // 如果是value,创建一个value的数据对象TypedStringvalue,这个对象封装了value的信息
        } else if (hasValueAttribute) {
            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));
            valueHolder.setSource(this.extractSource(ele));
            return valueHolder;
        // 如果还有子元素,触发对子元素的解析
        } else if (subElement != null) {
            return this.parsePropertySubElement(subElement, bd);
        } else {
            this.error(elementName + " must specify a ref or value", ele);
            return null;
        }
    }

3.9 解析property元素的子元素

    @Nullable
    public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {
        return this.parsePropertySubElement(ele, bd, (String)null);
    }
    @Nullable
    public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
        if (!this.isDefaultNamespace((Node)ele)) {
            return this.parseNestedCustomElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "bean")) {
            BeanDefinitionHolder nestedBd = this.parseBeanDefinitionElement(ele, bd);
            if (nestedBd != null) {
                nestedBd = this.decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
            }

            return nestedBd;
        } else if (this.nodeNameEquals(ele, "ref")) {
            String refName = ele.getAttribute("bean");
            boolean toParent = false;
            if (!StringUtils.hasLength(refName)) {
                refName = ele.getAttribute("parent");
                toParent = true;
                if (!StringUtils.hasLength(refName)) {
                    this.error("'bean' or 'parent' is required for <ref> element", ele);
                    return null;
                }
            }

            if (!StringUtils.hasText(refName)) {
                this.error("<ref> element contains empty target attribute", ele);
                return null;
            } else {
                RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
                ref.setSource(this.extractSource(ele));
                return ref;
            }
        } else if (this.nodeNameEquals(ele, "idref")) {
            return this.parseIdRefElement(ele);
        } else if (this.nodeNameEquals(ele, "value")) {
            return this.parseValueElement(ele, defaultValueType);
        } else if (this.nodeNameEquals(ele, "null")) {
            TypedStringValue nullHolder = new TypedStringValue((String)null);
            nullHolder.setSource(this.extractSource(ele));
            return nullHolder;
        } else if (this.nodeNameEquals(ele, "array")) {
            return this.parseArrayElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "list")) {
            return this.parseListElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "set")) {
            return this.parseSetElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "map")) {
            return this.parseMapElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "props")) {
            return this.parsePropsElement(ele);
        } else {
            this.error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
            return null;
        }
    }

3.10 属性之list元素的解析

    public List<Object> parseListElement(Element collectionEle, @Nullable BeanDefinition bd) {
        String defaultElementType = collectionEle.getAttribute("value-type");
        NodeList nl = collectionEle.getChildNodes();
        ManagedList<Object> target = new ManagedList(nl.getLength());
        target.setSource(this.extractSource(collectionEle));
        target.setElementTypeName(defaultElementType);
        target.setMergeEnabled(this.parseMergeAttribute(collectionEle));
        // 具体的List元素的解析过程
        this.parseCollectionElements(nl, target, bd, defaultElementType);
        return target;
    }
    protected void parseCollectionElements(NodeList elementNodes, Collection<Object> target, @Nullable BeanDefinition bd, String defaultElementType) {
    	// 遍历所有的元素节点,并判断其类型是否为Element
        for(int i = 0; i < elementNodes.getLength(); ++i) {
            Node node = elementNodes.item(i);
            if (node instanceof Element && !this.nodeNameEquals(node, "description")) {
            	// 加入到target中,target是一个ManageList,同时触发对下一层子元素的解析过程
                target.add(this.parsePropertySubElement((Element)node, bd, defaultElementType));
            }
        }

    }

4、向IoC容器注册BeanDefinition

4.1容器的数据结构

在这些动作完成以后,用户定义的BeanDefinition信息已经在IoC容器内建立起了自己的数据结构以及相应的数据表示,但此时这些数据还不能供IoC容器直接使用,需要在IoC容器中对这些BeanDefinition数据进行注册。

这个注册为IoC容器提供了更友好的使用方式,在DefaultListableBeanFactory中,是通过一个HashMap来持有载入的BeanDefinition的,这个HashMap的定义在DefaultListableBeanFactory中可以看到。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    @Nullable
    private static Class<?> javaxInjectProviderClass;
    private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories;
    @Nullable
    private String serializationId;
    private boolean allowBeanDefinitionOverriding = true;
    private boolean allowEagerClassLoading = true;
    @Nullable
    private Comparator<Object> dependencyComparator;
    private AutowireCandidateResolver autowireCandidateResolver;
    private final Map<Class<?>, Object> resolvableDependencies;
    
    // 通过这个HashMap来持有载入的BeanDefinition
    private final Map<String, BeanDefinition> beanDefinitionMap;
    
    private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders;
    private final Map<Class<?>, String[]> allBeanNamesByType;
    private final Map<Class<?>, String[]> singletonBeanNamesByType;
    private volatile List<String> beanDefinitionNames;
    private volatile Set<String> manualSingletonNames;
    @Nullable
    private volatile String[] frozenBeanDefinitionNames;
    private volatile boolean configurationFrozen;

    public DefaultListableBeanFactory() {
        this.autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;
        this.resolvableDependencies = new ConcurrentHashMap(16);
        // beanDefinitionMap的初始化使用了ConcurrentHashMap
        this.beanDefinitionMap = new ConcurrentHashMap(256);
        this.mergedBeanDefinitionHolders = new ConcurrentHashMap(256);
        this.allBeanNamesByType = new ConcurrentHashMap(64);
        this.singletonBeanNamesByType = new ConcurrentHashMap(64);
        this.beanDefinitionNames = new ArrayList(256);
        this.manualSingletonNames = new LinkedHashSet(16);
    }

4.2调用注册方法

通过前面的解析后,把解析结果放到BeanDefinition对象中,并设置到BeanDefinitionHolder对象中去,用BeanDefinitionHolder来完成向IOC容器注册。

	// 这里是处理BeanDefinition的地方,
	// 具体的处理委托给BeanDefinitionParserDelegate来完成
	// ele对应在Spring BeanDefinition中定义的XML元素
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    	// BeanDefinitionHolder是BeanDefinition对象的封装类
    	// 封装了BeanDefinition,Bean的名字和别名
    	// 用它来完成向IOC容器注册
    	// 得到这个BeanDefinitionHolder就意味着BeanDefinition
    	// 是通过BeanDefinitionParserDelegate对XML元素的信息
    	// 按照Spring的Bean规则进行解析得到的
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
            // 这里是向IOC容器注册解析得到BeanDefinition的地方
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }

			// 在BeanDefinition向IOC容器注册完以后,发送消息 
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }
    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                registry.registerAlias(beanName, alias);
            }
        }

    }

4.3详细注册过程

检查是否有同名的BeanDefinition已经在IoC容器中,
如果有同名BeanDefinition,但又不允许覆盖,那么会抛出异常

把Bean的名字存入到beanDifinitionNames的同时
把beanName作为Map的key
把BeanDefinition作为value
存入到IoC容器持有的beanDefinitionMap中去

    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 var8) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
            }
        }
		// 检查是否有同名的BeanDefinition已经在IoC容器中,
		// 如果有同名BeanDefinition,但又不允许覆盖,那么会抛出异常
        BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }

            if (existingDefinition.getRole() < beanDefinition.getRole()) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (!beanDefinition.equals(existingDefinition)) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (this.logger.isTraceEnabled()) {
                this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }

            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if (this.hasBeanCreationStarted()) {
                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;
                    this.removeManualSingletonName(beanName);
                }
            } else {
            	// 这是正常注册BeanDefinition的过程,
            	// 把Bean的名字存入到beanDifinitionNames的同时,
            	// 把beanName作为Map的key,
            	//把BeanDefinition作为value存入到IoC容器持有的beanDefinitionMap中去
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.removeManualSingletonName(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition == null && !this.containsSingleton(beanName)) {
            if (this.isConfigurationFrozen()) {
                this.clearByTypeCache();
            }
        } else {
            this.resetBeanDefinition(beanName);
        }

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值