因为我在研究Spring的IOC,不可避免的(我好幽默)要研究一下XmlBeanDefinitionReader,代码如下:
/* * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.xml; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.parsing.EmptyReaderEventListener; import org.springframework.beans.factory.parsing.FailFastProblemReporter; import org.springframework.beans.factory.parsing.NullSourceExtractor; import org.springframework.beans.factory.parsing.ProblemReporter; import org.springframework.beans.factory.parsing.ReaderEventListener; import org.springframework.beans.factory.parsing.SourceExtractor; import org.springframework.beans.factory.support.AbstractBeanDefinitionReader; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.Constants; import org.springframework.core.NamedThreadLocal; import org.springframework.core.io.DescriptiveResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.EncodedResource; import org.springframework.util.Assert; import org.springframework.util.xml.SimpleSaxErrorHandler; import org.springframework.util.xml.XmlValidationModeDetector; /** * Bean definition reader for XML bean definitions. * Delegates the actual XML document reading to an implementation * of the {@link BeanDefinitionDocumentReader} interface. * * <p>Typically applied to a * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory} * or a {@link org.springframework.context.support.GenericApplicationContext}. * * <p>This class loads a DOM document and applies the BeanDefinitionDocumentReader to it. * The document reader will register each bean definition with the given bean factory, * talking to the latter's implementation of the * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} interface. * * @author Juergen Hoeller * @author Rob Harrop * @author Chris Beams * @since 26.11.2003 * @see #setDocumentReaderClass * @see BeanDefinitionDocumentReader * @see DefaultBeanDefinitionDocumentReader * @see BeanDefinitionRegistry * @see org.springframework.beans.factory.support.DefaultListableBeanFactory * @see org.springframework.context.support.GenericApplicationContext */ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { /** * Indicates that the validation should be disabled. */ public static final int VALIDATION_NONE = XmlValidationModeDetector.VALIDATION_NONE; /** * Indicates that the validation mode should be detected automatically. */ public static final int VALIDATION_AUTO = XmlValidationModeDetector.VALIDATION_AUTO; /** * Indicates that DTD validation should be used. */ public static final int VALIDATION_DTD = XmlValidationModeDetector.VALIDATION_DTD; /** * Indicates that XSD validation should be used. */ public static final int VALIDATION_XSD = XmlValidationModeDetector.VALIDATION_XSD; /** Constants instance for this class */ private static final Constants constants = new Constants(XmlBeanDefinitionReader.class); private int validationMode = VALIDATION_AUTO; private boolean namespaceAware = false; private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class; private ProblemReporter problemReporter = new FailFastProblemReporter(); private ReaderEventListener eventListener = new EmptyReaderEventListener(); private SourceExtractor sourceExtractor = new NullSourceExtractor(); private NamespaceHandlerResolver namespaceHandlerResolver; private DocumentLoader documentLoader = new DefaultDocumentLoader(); private EntityResolver entityResolver; private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger); private final XmlValidationModeDetector validationModeDetector = new XmlValidationModeDetector(); private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded"); /** * Create new XmlBeanDefinitionReader for the given bean factory. * @param registry the BeanFactory to load bean definitions into, * in the form of a BeanDefinitionRegistry */ public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) { super(registry); } /** * Set whether to use XML validation. Default is <code>true</code>. * <p>This method switches namespace awareness on if validation is turned off, * in order to still process schema namespaces properly in such a scenario. * @see #setValidationMode * @see #setNamespaceAware */ public void setValidating(boolean validating) { this.validationMode = (validating ? VALIDATION_AUTO : VALIDATION_NONE); this.namespaceAware = !validating; } /** * Set the validation mode to use by name. Defaults to {@link #VALIDATION_AUTO}. * @see #setValidationMode */ public void setValidationModeName(String validationModeName) { setValidationMode(constants.asNumber(validationModeName).intValue()); } /** * Set the validation mode to use. Defaults to {@link #VALIDATION_AUTO}. * <p>Note that this only activates or deactivates validation itself. * If you are switching validation off for schema files, you might need to * activate schema namespace support explicitly: see {@link #setNamespaceAware}. */ public void setValidationMode(int validationMode) { this.validationMode = validationMode; } /** * Return the validation mode to use. */ public int getValidationMode() { return this.validationMode; } /** * Set whether or not the XML parser should be XML namespace aware. * Default is "false". * <p>This is typically not needed when schema validation is active. * However, without validation, this has to be switched to "true" * in order to properly process schema namespaces. */ public void setNamespaceAware(boolean namespaceAware) { this.namespaceAware = namespaceAware; } /** * Return whether or not the XML parser should be XML namespace aware. */ public boolean isNamespaceAware() { return this.namespaceAware; } /** * Specify which {@link org.springframework.beans.factory.parsing.ProblemReporter} to use. * <p>The default implementation is {@link org.springframework.beans.factory.parsing.FailFastProblemReporter} * which exhibits fail fast behaviour. External tools can provide an alternative implementation * that collates errors and warnings for display in the tool UI. */ public void setProblemReporter(ProblemReporter problemReporter) { this.problemReporter = (problemReporter != null ? problemReporter : new FailFastProblemReporter()); } /** * Specify which {@link ReaderEventListener} to use. * <p>The default implementation is EmptyReaderEventListener which discards every event notification. * External tools can provide an alternative implementation to monitor the components being * registered in the BeanFactory. */ public void setEventListener(ReaderEventListener eventListener) { this.eventListener = (eventListener != null ? eventListener : new EmptyReaderEventListener()); } /** * Specify the {@link SourceExtractor} to use. * <p>The default implementation is {@link NullSourceExtractor} which simply returns <code>null</code> * as the source object. This means that - during normal runtime execution - * no additional source metadata is attached to the bean configuration metadata. */ public void setSourceExtractor(SourceExtractor sourceExtractor) { this.sourceExtractor = (sourceExtractor != null ? sourceExtractor : new NullSourceExtractor()); } /** * Specify the {@link NamespaceHandlerResolver} to use. * <p>If none is specified, a default instance will be created through * {@link #createDefaultNamespaceHandlerResolver()}. */ public void setNamespaceHandlerResolver(NamespaceHandlerResolver namespaceHandlerResolver) { this.namespaceHandlerResolver = namespaceHandlerResolver; } /** * Specify the {@link DocumentLoader} to use. * <p>The default implementation is {@link DefaultDocumentLoader} * which loads {@link Document} instances using JAXP. */ public void setDocumentLoader(DocumentLoader documentLoader) { this.documentLoader = (documentLoader != null ? documentLoader : new DefaultDocumentLoader()); } /** * Set a SAX entity resolver to be used for parsing. * <p>By default, {@link ResourceEntityResolver} will be used. Can be overridden * for custom entity resolution, for example relative to some specific base path. */ public void setEntityResolver(EntityResolver entityResolver) { this.entityResolver = entityResolver; } /** * 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; } /** * Set an implementation of the <code>org.xml.sax.ErrorHandler</code> * interface for custom handling of XML parsing errors and warnings. * <p>If not set, a default SimpleSaxErrorHandler is used that simply * logs warnings using the logger instance of the view class, * and rethrows errors to discontinue the XML transformation. * @see SimpleSaxErrorHandler */ public void setErrorHandler(ErrorHandler errorHandler) { this.errorHandler = errorHandler; } /** * Specify the {@link BeanDefinitionDocumentReader} implementation to use, * responsible for the actual reading of the XML bean definition document. * <p>The default is {@link DefaultBeanDefinitionDocumentReader}. * @param documentReaderClass the desired BeanDefinitionDocumentReader implementation class */ public void setDocumentReaderClass(Class<?> documentReaderClass) { if (documentReaderClass == null || !BeanDefinitionDocumentReader.class.isAssignableFrom(documentReaderClass)) { throw new IllegalArgumentException( "documentReaderClass must be an implementation of the BeanDefinitionDocumentReader interface"); } this.documentReaderClass = documentReaderClass; } /** * 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 */ public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } /** * 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(); } } } /** * Load bean definitions from the specified XML file. * @param inputSource the SAX InputSource to read from * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ public int loadBeanDefinitions(InputSource inputSource) throws BeanDefinitionStoreException { return loadBeanDefinitions(inputSource, "resource loaded through SAX InputSource"); } /** * Load bean definitions from the specified XML file. * @param inputSource the SAX InputSource to read from * @param resourceDescription a description of the resource * (can be <code>null</code> or empty) * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ public int loadBeanDefinitions(InputSource inputSource, String resourceDescription) throws BeanDefinitionStoreException { return doLoadBeanDefinitions(inputSource, new DescriptiveResource(resourceDescription)); } /** * 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 */ protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); 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); } } /** * 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</code> * 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); } } /** * Register the bean definitions contained in the given DOM document. * Called by <code>loadBeanDefinitions</code>. * <p>Creates a new instance of the parser class and invokes * <code>registerBeanDefinitions</code> 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(); documentReader.setEnvironment(this.getEnvironment()); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } /** * Create the {@link BeanDefinitionDocumentReader} to use for actually * reading bean definitions from an XML document. * <p>The default implementation instantiates the specified "documentReaderClass". * @see #setDocumentReaderClass */ protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); } /** * Create the {@link XmlReaderContext} to pass over to the document reader. */ protected XmlReaderContext createReaderContext(Resource resource) { if (this.namespaceHandlerResolver == null) { this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, this.namespaceHandlerResolver); } /** * Create the default implementation of {@link NamespaceHandlerResolver} used if none is specified. * Default implementation returns an instance of {@link DefaultNamespaceHandlerResolver}. */ protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() { return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader()); } }
首先我来看一下属性部分:
/** * Indicates that the validation should be disabled. */ public static final int VALIDATION_NONE = XmlValidationModeDetector.VALIDATION_NONE; /** * Indicates that the validation mode should be detected automatically. */ public static final int VALIDATION_AUTO = XmlValidationModeDetector.VALIDATION_AUTO; /** * Indicates that DTD validation should be used. */ public static final int VALIDATION_DTD = XmlValidationModeDetector.VALIDATION_DTD; /** * Indicates that XSD validation should be used. */ public static final int VALIDATION_XSD = XmlValidationModeDetector.VALIDATION_XSD; /** Constants instance for this class */ private static final Constants constants = new Constants(XmlBeanDefinitionReader.class); private int validationMode = VALIDATION_AUTO; private boolean namespaceAware = false; private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class; private ProblemReporter problemReporter = new FailFastProblemReporter(); private ReaderEventListener eventListener = new EmptyReaderEventListener(); private SourceExtractor sourceExtractor = new NullSourceExtractor(); private NamespaceHandlerResolver namespaceHandlerResolver; private DocumentLoader documentLoader = new DefaultDocumentLoader(); private EntityResolver entityResolver; private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger); private final XmlValidationModeDetector validationModeDetector = new XmlValidationModeDetector(); private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded");
VALIDATION_NONE,表明验证应该禁用。
VALIDATION_AUTO,表明验证应该被自动检测到
VALIDATION_DTD,表明DTD验证应该被使用(关于DTD技术,这里躺着(我好幽默)一个链接http://blog.csdn.net/xiazdong/article/details/7270593)
VALIDATION_XSD,表明XSD验证应该被使用(关于XSD技术,这里又躺着(我好幽默)一个链接
http://blog.csdn.net/evanerv0079/article/details/2515313)
constants属性,是一个Constants,做什么用的呢?Constants构造函数如下:
/** * Create a new Constants converter class wrapping the given class. * <p>All <b>public</b> static final variables will be exposed, whatever their type. * @param clazz the class to analyze * @throws IllegalArgumentException if the supplied <code>clazz</code> is <code>null</code> */ public Constants(Class clazz) { Assert.notNull(clazz); this.className = clazz.getName(); Field[] fields = clazz.getFields(); for (Field field : fields) { if (ReflectionUtils.isPublicStaticFinal(field)) { String name = field.getName(); try { Object value = field.get(null); this.fieldCache.put(name, value); } catch (IllegalAccessException ex) { // just leave this field and continue } } } }
看到了没,just leave this field and continue这句话写的真好,这个类主要就是用来包装类的静态属性,放入一个Map集合,然后随去随用,因为这个属性也同样是static final的。
validationMode:默认下使用自动扫描的验证模式。
namespaceAware:false,表明不去发现命名空间?不确定,以后修改
documentReaderClass:用了和ApplicationContext关联紧密的DefaultBeanDefinitionDocumentReader类,有点意思。
problemReporter,对快速失败问题的报告类。
package org.springframework.beans.factory.parsing; /** * SPI interface allowing tools and other external processes to handle errors * and warnings reported during bean definition parsing. * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 * @see Problem */ public interface ProblemReporter { /** * Called when a fatal error is encountered during the parsing process. * <p>Implementations must treat the given problem as fatal, * i.e. they have to eventually raise an exception. * @param problem the source of the error (never <code>null</code>) */ void fatal(Problem problem); /** * Called when an error is encountered during the parsing process. * <p>Implementations may choose to treat errors as fatal. * @param problem the source of the error (never <code>null</code>) */ void error(Problem problem); /** * Called when a warning is raised during the parsing process. * <p>Warnings are <strong>never</strong> considered to be fatal. * @param problem the source of the warning (never <code>null</code>) */ void warning(Problem problem); }
源码表明对fetal(严重),error(错误),warning(警告)级别的错误信息分别处理生成报告。
eventListener:事件监听器,代码如下。
package org.springframework.beans.factory.parsing; import java.util.EventListener; /** * Interface that receives callbacks for component, alias and import * registrations during a bean definition reading process. * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 * @see ReaderContext */ public interface ReaderEventListener extends EventListener { /** * Notification that the given defaults has been registered. * @param defaultsDefinition a descriptor for the defaults * @see org.springframework.beans.factory.xml.DocumentDefaultsDefinition */ void defaultsRegistered(DefaultsDefinition defaultsDefinition); /** * Notification that the given component has been registered. * @param componentDefinition a descriptor for the new component * @see BeanComponentDefinition */ void componentRegistered(ComponentDefinition componentDefinition); /** * Notification that the given alias has been registered. * @param aliasDefinition a descriptor for the new alias */ void aliasRegistered(AliasDefinition aliasDefinition); /** * Notification that the given import has been processed. * @param importDefinition a descriptor for the import */ void importProcessed(ImportDefinition importDefinition); }
针对不同的定义,进行事件的监听,四个事件,DefaultsDefinition,ComponentDefinition,AliasDefinition,ImportDefinition,具体的实现可以查看源代码。默认将EmptyReaderEventListener监听器给了这个属性(幽默)。
sourceExtractor:代码如下
package org.springframework.beans.factory.parsing; import org.springframework.core.io.Resource; /** * Simple strategy allowing tools to control how source metadata is attached * to the bean definition metadata. * * <p>Configuration parsers <strong>may</strong> provide the ability to attach * source metadata during the parse phase. They will offer this metadata in a * generic format which can be further modified by a {@link SourceExtractor} * before being attached to the bean definition metadata. * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 * @see org.springframework.beans.BeanMetadataElement#getSource() * @see org.springframework.beans.factory.config.BeanDefinition */ public interface SourceExtractor { /** * Extract the source metadata from the candidate object supplied * by the configuration parser. * @param sourceCandidate the original source metadata (never <code>null</code>) * @param definingResource the resource that defines the given source object * (may be <code>null</code>) * @return the source metadata object to store (may be <code>null</code>) */ Object extractSource(Object sourceCandidate, Resource definingResource); }
Object extractSource(Object sourceCandidate, Resource definingResource);提取资源,通过的定的定义资源类型和投进去的资源。
namespaceHandlerResolver:NamespaceHandlerResolver类的一个属性名,用来解决命名空间的handler问题(白说),主要应该用来生成引用。
documentLoader:DocumentLoader类的属性名,用来加载document文档类型的source。
package org.springframework.beans.factory.xml; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; /** * Strategy interface for loading an XML {@link Document}. * * @author Rob Harrop * @since 2.0 * @see DefaultDocumentLoader */ public interface DocumentLoader { /** * Load a {@link Document document} from the supplied {@link InputSource source}. * @param inputSource the source of the document that is to be loaded * @param entityResolver the resolver that is to be used to resolve any entities * @param errorHandler used to report any errors during document loading * @param validationMode the type of validation * {@link org.springframework.util.xml.XmlValidationModeDetector#VALIDATION_DTD DTD} * or {@link org.springframework.util.xml.XmlValidationModeDetector#VALIDATION_XSD XSD}) * @param namespaceAware <code>true</code> if support for XML namespaces is to be provided * @return the loaded {@link Document document} * @throws Exception if an error occurs */ Document loadDocument( InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception; }
针对输入的Source,根据验证模式,是否命名空间说明,应用EntityResolver实体解决类加入ErrorHandler协助完成功能。
entityResolver:EntityResolver类的变量,针对上面一个属性已经用了它,暗示着这个EntityResolver只是一个蓝领工具类。
errorHandler:ErrorHandler类的变量,一样蓝领。
validationModeDetector:XmlValidationModeDetector类的变量,对xml验证模式的检测,是个很重要的属性哦!
package org.springframework.util.xml; import java.io.BufferedReader; import java.io.CharConversionException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.springframework.util.StringUtils; /** * Detects whether an XML stream is using DTD- or XSD-based validation. * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 */ public class XmlValidationModeDetector { /** * Indicates that the validation should be disabled. */ public static final int VALIDATION_NONE = 0; /** * Indicates that the validation mode should be auto-guessed, since we cannot find * a clear indication (probably choked on some special characters, or the like). */ public static final int VALIDATION_AUTO = 1; /** * Indicates that DTD validation should be used (we found a "DOCTYPE" declaration). */ public static final int VALIDATION_DTD = 2; /** * Indicates that XSD validation should be used (found no "DOCTYPE" declaration). */ public static final int VALIDATION_XSD = 3; /** * The token in a XML document that declares the DTD to use for validation * and thus that DTD validation is being used. */ private static final String DOCTYPE = "DOCTYPE"; /** * The token that indicates the start of an XML comment. */ private static final String START_COMMENT = "<!--"; /** * The token that indicates the end of an XML comment. */ private static final String END_COMMENT = "-->"; /** * Indicates whether or not the current parse position is inside an XML comment. */ private boolean inComment; /** * 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(); } } /** * Does the content contain the the DTD DOCTYPE declaration? */ private boolean hasDoctype(String content) { return (content.indexOf(DOCTYPE) > -1); } /** * Does the supplied content contain an XML opening tag. If the parse state is currently * in an XML comment then this method always returns false. It is expected that all comment * tokens will have consumed for the supplied content before passing the remainder to this method. */ private boolean hasOpeningTag(String content) { if (this.inComment) { return false; } int openTagIndex = content.indexOf('<'); return (openTagIndex > -1 && content.length() > openTagIndex && Character.isLetter(content.charAt(openTagIndex + 1))); } /** * Consumes all the leading comment data in the given String and returns the remaining content, which * may be empty since the supplied content might be all comment data. For our purposes it is only important * to strip leading comment content on a line since the first piece of non comment content will be either * the DOCTYPE declaration or the root element of the document. */ private String consumeCommentTokens(String line) { if (line.indexOf(START_COMMENT) == -1 && line.indexOf(END_COMMENT) == -1) { return line; } while ((line = consume(line)) != null) { if (!this.inComment && !line.trim().startsWith(START_COMMENT)) { return line; } } return line; } /** * Consume the next comment token, update the "inComment" flag * and return the remaining content. */ private String consume(String line) { int index = (this.inComment ? endComment(line) : startComment(line)); return (index == -1 ? null : line.substring(index)); } /** * Try to consume the {@link #START_COMMENT} token. * @see #commentToken(String, String, boolean) */ private int startComment(String line) { return commentToken(line, START_COMMENT, true); } private int endComment(String line) { return commentToken(line, END_COMMENT, false); } /** * Try to consume the supplied token against the supplied content and update the * in comment parse state to the supplied value. Returns the index into the content * which is after the token or -1 if the token is not found. */ private int commentToken(String line, String token, boolean inCommentIfPresent) { int index = line.indexOf(token); if (index > - 1) { this.inComment = inCommentIfPresent; } return (index == -1 ? index : index + token.length()); } }
主要根据输入流在缓冲区中对输入流携带的Token进行分类处理。
resourcesCurrentlyBeingLoaded:ThreadLocal的一个变量,很有趣的一个泛型类,ThreadLocal<Set<EncodedResource>>预示着你可以存储任何类型在这个对象实例中,但如何使用还未知。