• loadBeanDefinitions方法源码跟踪(一)


    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead

    代码过宽,可以shift + 鼠标滚轮 左右滑动查看

    AbstractBeanDefinitionReader类中loadBeanDefinitions方法,该方法会对DOM文档对象进行解析,生成BeanDefinition对象,这篇文章只讲这个方法。

    /**
    * Load bean definitions from the specified resources.
    * @param resources the resource descriptors 资源处理器,也叫做资源描述符
    * @return the number of bean definitions found 返回发现的bean definition数量
    * 
    * 从指定资源中加载bean definitions
    */
    @Override
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        
        //因为我的web.xml中配置contextConfigLocation不管classpath前缀还是后半部分
        //都没有使用 * 或者 ?等表达式,所以只有一个Resource--资源描述符,或者
        //称作资源处理器
        for (Resource resource : resources) {
            
            //调用的子类XmlBeanDefinitionReader方法,进入查看
            counter += loadBeanDefinitions(resource);
        }
        return counter;
    }
    
    /**
    * 此方法在AbstractBeanDefinitionReader的子类XmlBeanDefinitionReader中
    *
    * Load bean definitions from the specified XML file.
    * 从指定的xml文件中加载bean definitions
    */
    @Override
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(new EncodedResource(resource));
    }
    
    
    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());
        }
        
    	//resourcesCurrentlyBeingLoaded是一个ThreadLocal,里面存放Resource包装类的set集合
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        
        //如果set中已有这个元素则返回false,进入该条件抛出异常
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                
                //检测到循环加载某个Resource,需要检查导入的definitions
                "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 {
            
            //资源加载完毕,移除该Resource
            currentResources.remove(encodedResource);
            
            //如果集合中已经没有了其他Resource,移除集合
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }
    

    doLoadBeanDefinitions(零)

    此方法在XmlBeanDefinitionReader类中,分两部分跟踪

    /**
    * Actually load bean definitions from the specified XML file.
    * 
    * 真正的从指定xml文件中加载bean definitions
    */
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        throws BeanDefinitionStoreException {
        try {
            
            //根据不同的xml约束(dtd,xsd等),将xml文件生成对应的文档对象
            //1.这个方法里面涉及xml的解析		
            Document doc = doLoadDocument(inputSource, resource);
            
    	    //2.主要就是看这个方法,bean definitions的注册
            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);
        }
    }
    

    1.doLoadDocument

    跟踪标记1的方法

    此方法在XmlBeanDefinitionReader类中

    //1.这个方法里面涉及xml的解析		
    Document doc = doLoadDocument(inputSource, resource);
    
    
    /**
    * Actually load the specified document using the configured DocumentLoader.
    * @param inputSource the SAX InputSource to read from --从中读取的SAX输入源
    * @param resource the resource descriptor for the XML file --xml文件的资源描述符
    * @return the DOM Document DOM文档对象
    * 
    * 使用配置好的DocumentLoader文档加载器加载指定的文档
    */
    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                                                getValidationModeForResource(resource), isNamespaceAware());
    }
    

    上面方法入参说明一下:

    参一

    inputSource 由上一层方法传递过来。

    参二

    getEntityResolver() 方法返回 XmlBeanDefinitionReader 类的 entityResolver 属性。
    entityResolver 属性在 loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法中被赋值。

    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    

    this拿的是根web应用上下文,查看ResourceEntityResolver的构造方法

    /**
    * Create a ResourceEntityResolver for the specified ResourceLoader
    * (usually, an ApplicationContext).
    * @param resourceLoader the ResourceLoader (or ApplicationContext)
    * to load XML entity includes with
    * 
    * 为指定的ResourceLoade(通常是应用上下文)r创建一个ResourceEntityResolver
    */
    public ResourceEntityResolver(ResourceLoader resourceLoader) {
        super(resourceLoader.getClassLoader());
        
        //此处解析器拿到了上下文的引用
        this.resourceLoader = resourceLoader;
    }
    

    调用了父类构造,再跟进一层

    /**
    * Create a new DelegatingEntityResolver that delegates to
    * a default {@link BeansDtdResolver} and a default {@link PluggableSchemaResolver}.
    * <p>Configures the {@link PluggableSchemaResolver} with the supplied
    * {@link ClassLoader}.
    * @param classLoader the ClassLoader to use for loading
    * (can be {@code null}) to use the default ClassLoader)
    */
    public DelegatingEntityResolver(ClassLoader classLoader) {
        
        //这两个解析器和约束的类型有关,DTD
        this.dtdResolver = new BeansDtdResolver();
        
        //可插拔的Schema解析器,拿的上下文的类加载器
        this.schemaResolver = new PluggableSchemaResolver(classLoader);
    }
    

    参三

    再看doLoadDocument方法的另外一个入参 this.errorHandler,这个属性随着XmlBeanDefinitionReader类被初始化而初始化

    private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger);
    

    参四

    然后是getValidationModeForResource(resource)入参。

    /**
    * 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.
    * 
    * 通过给定Resource给出验证模式。如果没有明确配置验证模式,那么调用detectValidationMode方法去检测。
    */
    protected int getValidationModeForResource(Resource resource) {
        
        //默认自动验证,为1
        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).
        
        // 如果实在不能判断验证模式是那种就使用XSD方式,
        // 因为检测完后还是没有发现DTD模式的声明(在查找document的根标签之前)。
        // 值为3
        return VALIDATION_XSD;
    }
    

    进入下面这个方法,这个方法由XmlBeanDefinitionReader实现

    int detectedMode = detectValidationMode(resource);
    
    /**
    * 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.
    * 
    * 检测执行xml文件时该用哪种验证方式,这个xml由Resource对象提供
    * 如果这个文件有DOCTYPE声明,那么就用DTD验证,否则就假定使用XSD。
    * 如果你想要自定义自动验证模式的解决方式,你可以覆盖这个方法
    */
    protected int detectValidationMode(Resource resource) {
        
        //默认false
        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);
        }
    }
    

    XmlBeanDefinitionReader的validationModeDetector属性有默认实现

    private final XmlValidationModeDetector validationModeDetector = new XmlValidationModeDetector();
    

    validationModeDetector调用detectValidationMode方法

    /**
    * 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.
    * 
    * 在提供的InputStream中检测XML文档的验证模式
    * 注意,提供的InputStream在这个方法return之前会被关闭
    */
    public int detectValidationMode(InputStream inputStream) throws IOException {
        
        // Peek into the file to look for DOCTYPE.
        // 查找文件的DOCTYPE
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        try {
            boolean isDtdValidated = false;
            String content;
            while ((content = reader.readLine()) != null) {
                
                //读一行字符串就干掉字符串里面的注释,如果全是注释全干掉
                //主要为了剥离注释,因为非注释内容要么是DOCTYPE声明要么是文档的根元素对象
                content = consumeCommentTokens(content);
                
                //剥离注释后完全没内容就继续循环
                if (this.inComment || !StringUtils.hasText(content)) {
                    continue;
                }
                
                //有DOCTYPE声明,就跳出去
                if (hasDoctype(content)) {
                    isDtdValidated = true;
                    break;
                }
                
                //注释不能进去。开头是"<",后面第一个字符是字母,就进入。
                //比如'<beans xmlns="http://www.springframework.org/schema/beans"'
                //进去后跳出循环
                if (hasOpeningTag(content)) {
                    
                    // End of meaningful data...
                    break;
                }
            }
            
            //当遍历到名称空间了也就是"<beans xmlns=...>"还没有DOCTYPE声明,
            //那么就判定他为XSD验证
            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();
        }
    }
    

    我这么里用的XSD验证。也就是值为3,传递给loadDocument的入参

    参五

    最后一个入参,isNamespaceAware()

    /**
    * Return whether or not the XML parser should be XML namespace aware.
    *
    * XML解析器是否支持XML名称空间
    */
    public boolean isNamespaceAware() {
        return this.namespaceAware;
    }
    

    默认false

    看完五个参数后进入正主,loadDocument方法。

    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
    				getValidationModeForResource(resource), isNamespaceAware());
    

    documentLoader属性默认实现:

    private DocumentLoader documentLoader = new DefaultDocumentLoader();
    

    进入DefaultDocumentLoader类的loadDocument方法

    /**
    * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
    * XML parser.
    *
    * 使用标准JAXP配置XML解析器加载InputSource的Document对象
    */
    @Override
    public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
                                 ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
        
        //创建文档构建器工厂对象,并初始化一些属性
        //如果验证模式为XSD,那么强制支持XML名称空间,并加上schema属性
        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        
        //创建一个JAXP文档构建器
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        
        //按照XML文档解析给定inputSource的内容,然后返回一个新的DOM对象
        return builder.parse(inputSource);
    }
    

    这样就拿到了Document对象

    回到XmlBeanDefinitionReader类的doLoadBeanDefinitions方法

    2.registerBeanDefinitions

    跟踪标记2的方法

    //2.主要就是看这个方法,bean definitions的注册
    return registerBeanDefinitions(doc, resource);
    
    
    /**
    * 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.
    * 
    * 注册包含在给定DOM文档对象中的 bean definition
    * 被loadBeanDefinitions方法所调用
    * 解析class后创建一个新的实例,并调用registerBeanDefinitions方法
    */
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        
        //getRegistry()方法拿的是bean工厂对象,beanDefinition注册在工厂中
        //这个方法就是返回已经被注册在工厂中的beanDefinitions数量
        int countBefore = getRegistry().getBeanDefinitionCount();
        
        //进入这个方法查看
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        
        //返回上个方法真正注册在工厂中的beanDefinition数量
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    
    
    /**
    * 这个方法在刚创建的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.
    *
    * 根据“spring-beans"的XSD(或者DTD)去解析bean definition
    * 打开一个DOM文档,然后初始化在<beans/>层级上指定的默认设置,然后解析包含在其中的bean definitions
    */
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        
        //入参时创建的XmlReaderContext对象
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        
        //拿到了xml文档对象的根元素
        Element root = doc.getDocumentElement();
        
        //进入这个方法进行查看
        doRegisterBeanDefinitions(root);
    }
    

    查看DefaultBeanDefinitionDocumentReader类的doRegisterBeanDefinitions方法。

    /**
    * Register each bean definition within the given root {@code <beans/>} element.
    *
    * 在给定的根元素对象<beans/>中,注册每一个bean definition
    */
    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.
        
        // 任何被嵌套的<beans>元素都会导致此方法的递归。为了正确的传播和保存<beans>的默认属性、
        // 保持当前(父)代理的跟踪,它可能为null
        // 为了能够回退,新的(子)代理具有父的引用,最终会重置this.delegate回到它的初始(父)引用。
        // 这个行为模拟了一堆代理,但实际上并不需要一个代理
        BeanDefinitionParserDelegate parent = this.delegate;
        
        //2.1创建一个新的代理,并初始化一些默认值
        this.delegate = createDelegate(getReaderContext(), root, parent);
        
        //默认名称空间是"http://www.springframework.org/schema/beans"
        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            
            //我的xml文件中没有设置"profile",所以跳过
            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;
                }
            }
        }
        
        //xml预处理,子类没有重写里面就是空实现
        preProcessXml(root);
        
        //2.2生成BeanDefinition,并注册在工厂中
        parseBeanDefinitions(root, this.delegate);
        
        //xml后处理,子类没有重写里面就是空实现
        postProcessXml(root);
    
        this.delegate = parent;
    }
    

    2.1 createDelegate

    跟踪标记2.1的方法

    此方法在DefaultBeanDefinitionDocumentReader类中

    入参 getReaderContext() 方法返回的是先前创建的 XmlReaderContext 对象

    //2.1创建一个新的代理,并初始化一些默认值
    this.delegate = createDelegate(getReaderContext(), root, parent);
    
    
    protected BeanDefinitionParserDelegate createDelegate(
        XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
    	
        //用来解析XML bean definition的有状态代理类,用来被主解析器和其他扩展使用
        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
        
        //进入此方法
        delegate.initDefaults(root, parentDelegate);
        return delegate;
    }
    

    进入BeanDefinitionParserDelegate类的initDefaults方法

    /**
    * Initialize the default lazy-init, autowire, dependency check settings,
    * init-method, destroy-method and merge settings. Support nested 'beans'
    * element use cases by falling back to the given parent in case the
    * defaults are not explicitly set locally.
    * 
    * 初始化默认值 default :·······等
    * 通过使用 parent default,来解决嵌套的'beans'元素情况,以防 default 在局部设定不明确
    */
    public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
        
        //进入此方法
        populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
        
        //默认没做任何实现
        this.readerContext.fireDefaultsRegistered(this.defaults);
    }
    

    populateDefaults方法跟踪

    入参this.defaults有默认实现

    private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
    

    第二个入参:当第一次进入此方法时,parent为null。

    进入方法

    /**
    * Populate the given DocumentDefaultsDefinition instance with the default lazy-init,
    * autowire, dependency check settings, init-method, destroy-method and merge settings.
    * Support nested 'beans' element use cases by falling back to <literal>parentDefaults</literal>
    * in case the defaults are not explicitly set locally.
    *
    * 用默认的值填充DocumentDefaultsDefinition实例
    * 通过使用parentDefaults(父代理的default属性),来解决嵌套的'beans'元素情况,以防默认值在局部设定不明确
    */
    protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
        
        //根元素上如果没有设定值,则返回"default"字符串
        String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
        
        //如果为"default",先看parentDefaults有没有,有用它的,没有用"false"
        if (DEFAULT_VALUE.equals(lazyInit)) {
            
            // Potentially inherited from outer <beans> sections, otherwise falling back to false.
            
            // 可能从外部<beans>继承,否则返回false
            lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
        }
        defaults.setLazyInit(lazyInit);
    
        String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
        if (DEFAULT_VALUE.equals(merge)) {
            
            // Potentially inherited from outer <beans> sections, otherwise falling back to false.
            merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
        }
        defaults.setMerge(merge);
    
        String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
        if (DEFAULT_VALUE.equals(autowire)) {
            
            // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
            autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
        }
        defaults.setAutowire(autowire);
    
        // Don't fall back to parentDefaults for dependency-check as it's no longer supported in
        // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
        
        // 依赖检查不会采用parentDefaults,因为在3.0之后已不再支持。因此,嵌套的<beans>不会使用parentDefaults
        defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
    
        if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
            defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
        }
        else if (parentDefaults != null) {
            defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
        }
    
        if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
            defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
        }
        else if (parentDefaults != null) {
            defaults.setInitMethod(parentDefaults.getInitMethod());
        }
    
        if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
            defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
        }
        else if (parentDefaults != null) {
            defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
        }
        
    	//extractSource方法这里没有做任何实现,默认返回null
        defaults.setSource(this.readerContext.extractSource(root));
    }
    

    2.2 parseBeanDefinitions

    跟踪标记2.2的方法

    在DefaultBeanDefinitionDocumentReader类中

    //2.2生成BeanDefinition,并注册在工厂中
    parseBeanDefinitions(root, this.delegate);
    
    /**
    * Parse the elements at the root level in the document:
    * "import", "alias", "bean".
    *
    * 解析在文档中根层级的元素:"import", "alias", "bean".
    */
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        
        //默认名称空间是"http://www.springframework.org/schema/beans"
        //进入条件
        if (delegate.isDefaultNamespace(root)) {
            
            //获取根元素下的子Node,注意,Node不一定是子标签,可能是回车,可能是注释
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    
                    //拿到了<beans>下的子标签
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        
                        //3.如果该标签属于beans的名称空间,则进入这个方法
                        //xmlns="http://www.springframework.org/schema/beans"
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        
                        //4.如果该标签属于其他的名称空间比如:context,aop等
                        //xmlns:aop="http://www.springframework.org/schema/aop"
                        //xmlns:context="http://www.springframework.org/schema/context"
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }
    

    一个名称空间对应一个处理器。

    比如在spring的配置文件applicatinoContext.xml中加入了这行代码:

    <!-- 启用注解 -->
    <context:annotation-config />
    

    可以知道,标签annotation-config属于名称空间context。

    那么context就对应着一个处理器。

    解析的时候会先获取context对应的处理器。处理器中又会初始化一些解析器出来,一个解析器就对应着一个标签,像annotation-config就有对应自己的解析器。

    不同的名称空间、不同的标签导致解析的方式非常的多,这里只拿两个常见的配置进行跟踪。

    因为字数超过了限制,所以分成了三篇,点击下篇继续阅读
    https://www.jianshu.com/p/46e27afd7d96

    总结

    • 解析 Resource 对象,生成DOM文档对象
    • 2 注册BeanDefinitions

    ——————————————————————————————————

    • 2
    • 创建新的 delegate 对象,delegate 中有 defaults 属性,它是标签元素属性的一个集合。如果当前 Reader 对象中也有 delegate ,将其作为 parent 。取 parent 的 defaults ,作为未指定标签元素属性的情况下,新 defaults 的默认值。
    • 根据名称空间不同,分为beans默认名称空间的元素解析,和其他自定义元素解析。一般来说,一个名称空间对应一个处理器,处理器中又会初始化一些解析器出来。一个解析器就对应着一个标签,可以对不同的情况进行解析。
  • 相关阅读:
    python实战===用python调用jar包
    Django连接数据库写入数据报错
    Niginx主配置文件参数详解
    uwsgi参数详解
    JSON序列化和反序列化
    ServiceBroker创建流程
    WCF和WebService中获取当前请求报文的方法
    python 关于文件的操作
    关于函数对象的理解
    python,关于用户登录与注册问题
  • 原文地址:https://www.cnblogs.com/feng-jq/p/10282196.html
Copyright © 2020-2023  润新知