1、loadBeanDefinitions(Resource resource) 从指定的XML文件加载bean定义。
1 2 3 4 5 6 7 8 9 10 @Override public int loadBeanDefinitions (Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource (resource)); }
首先将Resource包装成EncodeResource:将Resource描述符与用于从资源中读取的特定编码组合在一起,之后调用loadBeanDefinitions(EncodedResource encodedResource)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 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); } 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 { 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(); } } }
核心流程方法。用于解析资源为Document对象,并注册BeanDefinition。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } }
使用配置的DocumentLoader实际加载指定的文档。
1 2 3 4 5 6 7 protected Document doLoadDocument (InputSource inputSource, Resource resource) throws Exception { return this .documentLoader.loadDocument(inputSource, getEntityResolver(), this .errorHandler, getValidationModeForResource(resource), isNamespaceAware()); }
首先返回要使用的EntityResolver,如果没有指定,则构建默认的解析器。
1 2 3 4 5 6 7 8 9 10 11 12 protected EntityResolver getEntityResolver () { if (this .entityResolver == null ) { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader != null ) { this .entityResolver = new ResourceEntityResolver (resourceLoader); } else { this .entityResolver = new DelegatingEntityResolver (getBeanClassLoader()); } } return this .entityResolver; }
确定指定的{@link Resource}的验证模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected int getValidationModeForResource (Resource resource) { int validationModeToUse = getValidationMode(); if (validationModeToUse != VALIDATION_AUTO) { return validationModeToUse; } int detectedMode = detectValidationMode(resource); if (detectedMode != VALIDATION_AUTO) { return detectedMode; } return VALIDATION_XSD; }
返回XML解析器是否应该感知XML名称空间。
1 2 3 4 public boolean isNamespaceAware () { return this .namespaceAware; }
loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) 使用标准的JAXP-configured的XML解析器在提供的InputSource中加载Document。
1 2 3 4 5 6 7 8 9 10 11 12 13 @Override public Document loadDocument (InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isTraceEnabled()) { logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]" ); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); }
主要用了javax.xml包下的类,通过上面的这几步,获取到Document对象(org.w3c.dom包下类)。
下面来分析BeanDefinition加载的另一个步骤:注册。
2.2、registerBeanDefinitions(Document doc, Resource resource) 注册给定DOM文档中包含的bean定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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; } @Override public void registerBeanDefinitions (Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement()); }
下面分析核心流程:在给定的根 元素中注册每个bean定义。 doRegisterBeanDefinitions(Element root)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 @SuppressWarnings("deprecation") protected void doRegisterBeanDefinitions (Element root) { 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.isDebugEnabled()) { logger.debug("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; }
解析文档根级别的元素:”import”, “alias”, “bean”.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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); } }