美文网首页
Spring-IOC-BeanDefinition的解析并注册源

Spring-IOC-BeanDefinition的解析并注册源

作者: zhanglbjames | 来源:发表于2017-09-03 19:51 被阅读0次

    1- 资源的定位与封装(Resource)

    1.1 ClassPathResource初始化
     core.io.ClassPathResource
    
        public ClassPathResource(String path) {
            this(path, (ClassLoader) null);
        }
        /**
         * Create a new {@code ClassPathResource} for {@code ClassLoader} usage.
         * A leading slash will be removed, as the ClassLoader resource access
         * methods will not accept it.
         * @param path the absolute path within the classpath
         * @param classLoader the class loader to load the resource with,
         * or {@code null} for the thread context class loader
         * @see ClassLoader#getResourceAsStream(String)
         */
        public ClassPathResource(String path, ClassLoader classLoader) {
            Assert.notNull(path, "Path must not be null");
            String pathToUse = StringUtils.cleanPath(path);
            if (pathToUse.startsWith("/")) {
                pathToUse = pathToUse.substring(1);
            }
            this.path = pathToUse;
            this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
        }
    
    1.2 对Resource进行编码
    beans.factory.xml.XmlBeanFactory
    
        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);
        }
    
    beans.factory.xml.XmlBeanDefinitionReader   
        /**
         * Load bean definitions from the specified XML file.
         * @param resource the resource descriptor for the XML file
         * @return the number of bean definitions found
         * @throws BeanDefinitionStoreException in case of loading or parsing errors
         */
        @Override
        public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
            return loadBeanDefinitions(new EncodedResource(resource));
        }
    
    core.io.support.EncodedResource
        /**
         * Create a new {@code EncodedResource} for the given {@code Resource},
         * not specifying an explicit encoding or {@code Charset}.
         * @param resource the {@code Resource} to hold (never {@code null})
         */
        public EncodedResource(Resource resource) {
            this(resource, null, null);
        }
        private EncodedResource(Resource resource, String encoding, Charset charset) {
            super();
            Assert.notNull(resource, "Resource must not be null");
            this.resource = resource;
            this.encoding = encoding;
            this.charset = charset;
        }
    

    EncodedResource类有一个getReader方法,以指定的编码方式创建InputStreamReader。

    1.3 获取Resource编码后的sax.InputStream(有重复加载检测)
    beans.factory.xml.XmlBeanDefinitionReader
        /**
         * Load bean definitions from the specified XML file.
         * @param encodedResource the resource descriptor for the XML file,
         * allowing to specify an encoding to use for parsing the file
         * @return the number of bean definitions found
         * @throws BeanDefinitionStoreException in case of loading or parsing errors
         */
        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!");
            }
            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();
                }
            }
        }
        /**
         * Actually load bean definitions from the specified XML file.
         * @param inputSource the SAX InputSource to read from
         * @param resource the resource descriptor for the XML file
         * @return the number of bean definitions found
         * @throws BeanDefinitionStoreException in case of loading or parsing errors
         * @see #doLoadDocument
         * @see #registerBeanDefinitions
         */
        protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
            try {
                Document doc = doLoadDocument(inputSource, resource);
                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);
            }
        }
    

    2- 验证XML与解析XML输入流(sax.InputStream)

    2.1- 获取XML文件的验证模式
    beans.factory.xml.XmlBeanDefinitionReader
        /**
         * Gets the validation mode for the specified {@link Resource}. If no explicit
         * validation mode has been configured then the validation mode is
         * {@link #detectValidationMode detected}.
         * <p>Override this method if you would like full control over the validation
         * mode, even when something other than {@link #VALIDATION_AUTO} was set.
         */
        protected int getValidationModeForResource(Resource resource) {
            int validationModeToUse = getValidationMode();
            if (validationModeToUse != VALIDATION_AUTO) {
                return validationModeToUse;
            }
            int detectedMode = detectValidationMode(resource);
            if (detectedMode != VALIDATION_AUTO) {
                return detectedMode;
            }
            // Hmm, we didn't get a clear indication... Let's assume XSD,
            // since apparently no DTD declaration has been found up until
            // detection stopped (before finding the document's root tag).
            return VALIDATION_XSD;
        }
        /**
         * Detects which kind of validation to perform on the XML file identified
         * by the supplied {@link Resource}. If the file has a {@code DOCTYPE}
         * definition then DTD validation is used otherwise XSD validation is assumed.
         * <p>Override this method if you would like to customize resolution
         * of the {@link #VALIDATION_AUTO} mode.
         */
        protected int detectValidationMode(Resource resource) {
            if (resource.isOpen()) {
                throw new BeanDefinitionStoreException(
                        "Passed-in Resource [" + resource + "] contains an open stream: " +
                        "cannot determine validation mode automatically. Either pass in a Resource " +
                        "that is able to create fresh streams, or explicitly specify the validationMode " +
                        "on your XmlBeanDefinitionReader instance.");
            }
    
            InputStream inputStream;
            try {
                inputStream = resource.getInputStream();
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
                        "Did you attempt to load directly from a SAX InputSource without specifying the " +
                        "validationMode on your XmlBeanDefinitionReader instance?", ex);
            }
    
            try {
                return this.validationModeDetector.detectValidationMode(inputStream);
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +
                        resource + "]: an error occurred whilst reading from the InputStream.", ex);
            }
        }
    
    
    util.xml.XmlValidationModeDetector
        /**
         * Detect the validation mode for the XML document in the supplied {@link InputStream}.
         * Note that the supplied {@link InputStream} is closed by this method before returning.
         * @param inputStream the InputStream to parse
         * @throws IOException in case of I/O failure
         * @see #VALIDATION_DTD
         * @see #VALIDATION_XSD
         */
        public int detectValidationMode(InputStream inputStream) throws IOException {
            // Peek into the file to look for DOCTYPE.
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            try {
                boolean isDtdValidated = false;
                String content;
                while ((content = reader.readLine()) != null) {
                    content = consumeCommentTokens(content);
                    if (this.inComment || !StringUtils.hasText(content)) {
                        continue;
                    }
                    if (hasDoctype(content)) {
                        isDtdValidated = true;
                        break;
                    }
                    if (hasOpeningTag(content)) {
                        // End of meaningful data...
                        break;
                    }
                }
                return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
            }
            catch (CharConversionException ex) {
                // Choked on some character encoding...
                // Leave the decision up to the caller.
                return VALIDATION_AUTO;
            }
            finally {
                reader.close();
            }
        }
    

    Bean配置文件的两种验证模式:DTD、XSD

    XmlBeanDefinitionReader委托给XmlValidationModeDetector#validationModeDetector(inputStream)方法

    1. 检查是否设定了指定的验证模式(XmlBeanDefinitionReader#setValidationMode方法进行设定),
      如果设定了按照指定的验证方式进行验证
    2. 如果没有指定,则自动检测验证模式。检测方法为判断是否包含DOCTYPE,如果包含就是DTD,否则就是XSD
    2.2- 加载XML文件,并从sax.InputStream中得到对应的Document对象
        /**
         * Actually load the specified document using the configured DocumentLoader.
         * @param inputSource the SAX InputSource to read from
         * @param resource the resource descriptor for the XML file
         * @return the DOM Document
         * @throws Exception when thrown from the DocumentLoader
         * @see #setDocumentLoader
         * @see DocumentLoader#loadDocument
         */
        protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
            return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                    getValidationModeForResource(resource), isNamespaceAware());
        }
    
        /**
         * Return the EntityResolver to use, building a default resolver
         * if none specified.
         */
        protected EntityResolver getEntityResolver() {
            if (this.entityResolver == null) {
                // Determine default EntityResolver to use.
                ResourceLoader resourceLoader = getResourceLoader();
                if (resourceLoader != null) {
                    this.entityResolver = new ResourceEntityResolver(resourceLoader);
                }
                else {
                    this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
                }
            }
            return this.entityResolver;
        }
    beans.factory.xml.BeansDtdResolver
        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws IOException {
            if (logger.isTraceEnabled()) {
                logger.trace("Trying to resolve XML entity with public ID [" + publicId +
                        "] and system ID [" + systemId + "]");
            }
            if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
                int lastPathSeparator = systemId.lastIndexOf("/");
                int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
                if (dtdNameStart != -1) {
                    String dtdFile = DTD_FILENAME + DTD_EXTENSION;
                    if (logger.isTraceEnabled()) {
                        logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
                    }
                    try {
                        Resource resource = new ClassPathResource(dtdFile, getClass());
                        InputSource source = new InputSource(resource.getInputStream());
                        source.setPublicId(publicId);
                        source.setSystemId(systemId);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
                        }
                        return source;
                    }
                    catch (IOException ex) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
                        }
                    }
    
                }
            }
    
            // Use the default behavior -> download from website or wherever.
            return null;
        }
    beans.factory.xml.PluggableSchemaResolver
        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws IOException {
            if (logger.isTraceEnabled()) {
                logger.trace("Trying to resolve XML entity with public id [" + publicId +
                        "] and system id [" + systemId + "]");
            }
    
            if (systemId != null) {
                String resourceLocation = getSchemaMappings().get(systemId);
                if (resourceLocation != null) {
                    Resource resource = new ClassPathResource(resourceLocation, this.classLoader);
                    try {
                        InputSource source = new InputSource(resource.getInputStream());
                        source.setPublicId(publicId);
                        source.setSystemId(systemId);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Found XML schema [" + systemId + "] in classpath: " + resourceLocation);
                        }
                        return source;
                    }
                    catch (FileNotFoundException ex) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Couldn't find XML schema [" + systemId + "]: " + resource, ex);
                        }
                    }
                }
            }
            return null;
        }
    
    
    • 使用指定的验证模式,从sax.inputStream中解析Document对象,以便接下来解析其中的Element。

    • EntityResolver用来根据XML文档上的验证文件的声明,定位寻找本地DTD声明文件,主要是通过截取XML声明中的xx.dtd,然后去当前路径上寻找。

    4- 从Document中定位Root元素开始解析BeanDefinition

    beans.factory.xml.XmlBeanDefinitionReader
        /**
         * Register the bean definitions contained in the given DOM document.
         * Called by {@code loadBeanDefinitions}.
         * <p>Creates a new instance of the parser class and invokes
         * {@code registerBeanDefinitions} on it.
         * @param doc the DOM document
         * @param resource the resource descriptor (for context information)
         * @return the number of bean definitions found
         * @throws BeanDefinitionStoreException in case of parsing errors
         * @see #loadBeanDefinitions
         * @see #setDocumentReaderClass
         * @see BeanDefinitionDocumentReader#registerBeanDefinitions
         */
        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            int countBefore = getRegistry().getBeanDefinitionCount();
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }
        /**
         * Create the {@link XmlReaderContext} to pass over to the document reader.
         */
        public XmlReaderContext createReaderContext(Resource resource) {
            return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
                    this.sourceExtractor, this, getNamespaceHandlerResolver());
        }
    
    beans.factory.xml.DefaultBeanDefinitionDocumentReader
        /**
         * This implementation parses bean definitions according to the "spring-beans" XSD
         * (or DTD, historically).
         * <p>Opens a DOM Document; then initializes the default settings
         * specified at the {@code <beans/>} level; then parses the contained bean definitions.
         */
        @Override
        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            logger.debug("Loading bean definitions");
            Element root = doc.getDocumentElement();
            doRegisterBeanDefinitions(root);
        }
    
        /**
         * Register each bean definition within the given root {@code <beans/>} element.
         */
        protected void doRegisterBeanDefinitions(Element root) {
            // Any nested <beans> elements will cause recursion in this method. In
            // order to propagate and preserve <beans> default-* attributes correctly,
            // keep track of the current (parent) delegate, which may be null. Create
            // the new (child) delegate with a reference to the parent for fallback purposes,
            // then ultimately reset this.delegate back to its original (parent) reference.
            // this behavior emulates a stack of delegates without actually necessitating one.
            BeanDefinitionParserDelegate parent = this.delegate;
            this.delegate = createDelegate(getReaderContext(), root, parent);
    
            if (this.delegate.isDefaultNamespace(root)) {
                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);
            parseBeanDefinitions(root, this.delegate);
            postProcessXml(root);
    
            this.delegate = parent;
        }
        /**
         * Parse the elements at the root level in the document:
         * "import", "alias", "bean".
         * @param root the DOM root element of the document
         */
        protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            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);
            }
        }
    
    

    将获取到的root元素传递给doRegisterBeanDefinition(root)方法,并进行真正的Bean的解析阶段

    1. 处理profile属性(profile属性为Bean指定一个分类,可以在web.xml配置文件中只激活指定分类的Bean,这样可以对生产环境和开发环境进行隔离)

    2. 解析前处理(模板钩子方法,当前为空方法,留给子类实现)

    3. 将获得root元素和元素解析器delegate传递给parseBeanDefinitions(root,this.delegate)

      • 通过调用parseDefaultElement(ele,delegate)对默认命令空间进行解析
      • 通过调用delegate.parseCustomElement(root)对自定义命名空间进行解析
    4. 解析后处理(模板钩子方法,当前为空方法,留给子类实现)

    默认元素解析见: Spring默认标签解析

    5- 注册BeanDefinition

    通过上述的解析和装饰,已经得到了满足注册条件的BeanDefinition

    将解析出来的BeanDefinition注册到BeandDefinitionRegistry类型的实例registry中。

    对BeanDefinition注册分为两个部分

    1. 通过beanName的注册
    • 对AbstractBeanDefinition进行验证,此次验证不是验证Xml的格式,而是验证AbstractBeanDefinition额methodOverrides属性的
    • 对beanName已经注册的情况的处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖。
    • 加入BeanFactory的map缓存中
    • 清除解析之前留下的对应的beanName的缓存
    1. 通过别名的注册
    • alias与beanName相同:删除掉原有的alias
    • alias覆盖处理。若aliasName已经被其他的beanName所使用,则需要根据用户的设置进行相应的处理
      如果不允许覆盖则抛出异常IllegalStateException
    • alias循环检查:当A->B存在时,若再出现 A->C->B则会抛出异常
    • 注册alias
    2 注册解析出来的BeanDefinition
    beans.factory.support.BeanDefinitionReaderUtils 
        /**
         * Register the given bean definition with the given bean factory.
         * @param definitionHolder the bean definition including name and aliases
         * @param registry the bean factory to register with
         * @throws BeanDefinitionStoreException if registration failed
         */
        public static void registerBeanDefinition(
                BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
                throws BeanDefinitionStoreException {
    
            // Register bean definition under primary name.
            String beanName = definitionHolder.getBeanName();
            registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
            // Register aliases for bean name, if any.
            String[] aliases = definitionHolder.getAliases();
            if (aliases != null) {
                for (String alias : aliases) {
                    registry.registerAlias(beanName, alias);
                }
            }
        }
    
    2.1 通过beanName注册BeanDefinition
    beans.factory.suppor.DefaultListableBeanFactory(XmlBeanFactory继承此类)
        //---------------------------------------------------------------------
        // 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);
            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);
            }
            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);
            }
        }
    
    2.2 根据别名注册
    core.SimpleAliasRegistry(XmlBeanFactory继承此类)
        @Override
        public void registerAlias(String name, String alias) {
            Assert.hasText(name, "'name' must not be empty");
            Assert.hasText(alias, "'alias' must not be empty");
            if (alias.equals(name)) {
                this.aliasMap.remove(alias);
            }
            else {
                String registeredName = this.aliasMap.get(alias);
                if (registeredName != null) {
                    if (registeredName.equals(name)) {
                        // An existing alias - no need to re-register
                        return;
                    }
                    if (!allowAliasOverriding()) {
                        throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                                name + "': It is already registered for name '" + registeredName + "'.");
                    }
                }
                checkForAliasCircle(name, alias);
                this.aliasMap.put(alias, name);
            }
        }
    

    6- 通知与解析注册完成相关的监听器

    调用方法:getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));完成注册通知相应的监听器

    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    

    相关文章

      网友评论

          本文标题:Spring-IOC-BeanDefinition的解析并注册源

          本文链接:https://www.haomeiwen.com/subject/tkvjjxtx.html