XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource inputSource, Resource resource)解析过程

    科技2024-09-27  16

    以下几个常见的Spring加载bean的相关类,一定要熟悉,面试官可以不问你,但你不能不会~

     接口定义org.springframework.beans.factory.support.BeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)

    实现类

    我们关注Xml文件的读取,点开查看;

     org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)

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

    对Resource资源进行了一层封装,主要是为了对 Resource 进行编码,保证内容读取的正确性

    接着继续点进去

    /** * 当前线程,正在加载的 EncodedResource 集合。 */ private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<>("XML bean definition resources currently being loaded"); public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isTraceEnabled()) { logger.trace("Loading XML bean definitions from " + encodedResource); } // <1> 获取已经加载过的资源 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { // 将当前资源加入记录中。如果已存在,抛出异常 throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { // <2> 从 EncodedResource 获取封装的 Resource ,并从 Resource 中获取其中的 InputStream InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { // 设置编码 inputSource.setEncoding(encodedResource.getEncoding()); } // 核心逻辑部分,执行加载 BeanDefinition return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { // 从缓存中剔除该资源 <3> currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }

    通过 resourcesCurrentlyBeingLoaded.get() 代码,来获取已经加载过的资源,然后将 encodedResource 加入其中,如果 resourcesCurrentlyBeingLoaded 中已经存在该资源,则抛出 BeanDefinitionStoreException 异常。

    避免一个 EncodedResource 在加载时,还没加载完成,又加载自身,从而导致死循环。

    从 encodedResource 获取封装的 Resource 资源,并从 Resource 中获取相应的 InputStream ,然后将 InputStream 封装为 InputSource ,最后调用 #doLoadBeanDefinitions(InputSource inputSource, Resource resource) 方法,执行加载 Bean Definition 的真正逻辑。

    org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions

    /** * 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 { // <1> 获取 XML Document 实例 Document doc = doLoadDocument(inputSource, resource); // <2> 根据 Document 实例,注册 Bean 信息 int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } 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); } }

    org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadDocument 

    /** * 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()); }

    获取指定资源(xml)的验证模式,获取 XML Document 实例

    org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions

    // AbstractBeanDefinitionReader.java private final BeanDefinitionRegistry registry; // XmlBeanDefinitionReader.java public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // <1> 创建 BeanDefinitionDocumentReader 对象 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // <2> 获取已注册的 BeanDefinition 数量 int countBefore = getRegistry().getBeanDefinitionCount(); // <3> 创建 XmlReaderContext 对象 // <4> 注册 BeanDefinition documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 计算新注册的 BeanDefinition 数量 return getRegistry().getBeanDefinitionCount() - countBefore; }

    调用 #createBeanDefinitionDocumentReader() 方法,实例化 BeanDefinitionDocumentReader 对象。定义读取 Document 并注册 BeanDefinition 功能

    <2> 处,调用 BeanDefinitionRegistry#getBeanDefinitionCount() 方法,获取已注册的 BeanDefinition 数量。<3> 处,调用 #createReaderContext(Resource resource) 方法,创建 XmlReaderContext 对象。<4> 处,调用 BeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext) 方法,读取 XML 元素,注册 BeanDefinition 们。<5> 处,计算新注册的 BeanDefinition 数量。

    createBeanDefinitionDocumentReader

    /** * documentReader 的类 * * @see #createBeanDefinitionDocumentReader() */ private Class<? extends BeanDefinitionDocumentReader> documentReaderClass = DefaultBeanDefinitionDocumentReader.class; protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanUtils.instantiateClass(this.documentReaderClass); }

     

    public interface BeanDefinitionDocumentReader { /** * Read bean definitions from the given DOM document and * register them with the registry in the given reader context. * @param doc the DOM document * @param readerContext the current context of the reader * (includes the target registry and the resource being parsed) * @throws BeanDefinitionStoreException in case of parsing errors */ void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException; }

    从给定的 Document 对象中解析定义的 BeanDefinition 并将他们注册到注册表中

    DefaultBeanDefinitionDocumentReader

    @Nullable private XmlReaderContext readerContext; @Nullable private BeanDefinitionParserDelegate delegate; /** * 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; // 获得 XML Document Root Element // 执行注册 BeanDefinition doRegisterBeanDefinitions(doc.getDocumentElement()); } /** * Register each bean definition within the given root {@code <beans/>} element. */ @SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...) 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 对象 BeanDefinitionParserDelegate parent = this.delegate; // <1> 创建 BeanDefinitionParserDelegate 对象,并进行设置到 delegate this.delegate = createDelegate(getReaderContext(), root, parent); // <2> 检查 <beans /> 根标签的命名空间是否为空,或者是 http://www.springframework.org/schema/beans if (this.delegate.isDefaultNamespace(root)) { // <2.1> 处理 profile 属性。可参见《Spring3自定义环境配置 <beans profile="">》http://nassir.iteye.com/blog/1535799 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { // <2.2> 使用分隔符切分,可能有多个 profile 。 String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // <2.3> 如果所有 profile 都无效,则不进行注册 // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458 for details. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } // <3> 解析前处理 preProcessXml(root); // <4> 解析 parseBeanDefinitions(root, this.delegate); // <5> 解析后处理 postProcessXml(root); // 设置 delegate 回老的 BeanDefinitionParserDelegate 对象 this.delegate = parent; }

    <1> 处,创建 BeanDefinitionParserDelegate 对象,并进行设置到 delegate 。BeanDefinitionParserDelegate 是一个重要的类,它负责解析 BeanDefinition

    protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) { // 创建 BeanDefinitionParserDelegate 对象 BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); // 初始化默认 delegate.initDefaults(root, parentDelegate); return delegate; }

    parseBeanDefinitions

    /** * 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) { // <1> 如果根节点使用默认命名空间,执行默认解析 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; // <1> 如果该节点使用默认命名空间,执行默认解析 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); // 如果该节点非默认命名空间,执行自定义解析 } else { delegate.parseCustomElement(ele); } } } // <2> 如果根节点非默认命名空间,执行自定义解析 } else { delegate.parseCustomElement(root); } } private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // import importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // alias processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // bean processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // beans // recurse doRegisterBeanDefinitions(ele); } }

     

     

    Processed: 0.009, SQL: 8