zoukankan      html  css  js  c++  java
  • Spring 源码分析(二)--容器的基本实现

        容器最基本的实现是beanFactory,但是大部分企业引用都是使用ApplicationContext,这里介绍基础的BeanFactory是为了更好的理解spring内部原理。

    (一)基本用法

    (1)bean的声明

    package com.ws.learn.entity;
    
    public class Person {
        private String name;
        private Integer age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public void info(){
            System.out.println("name:"+getName()+" age:"+getAge());
        }
    }

    (2)配置文件beanFactoryTest.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="person" class="com.ws.learn.entity.Person">
            <property name="name" value="test"/>
            <property name="age" value="18"/>
        </bean>
    </beans>

    (3)测试

    public class MyTest {
        public static void main(String[] args){
            BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));//读取beanFactoryTest.xml中的内容
            Person p = bf.getBean("person",Person.class);
            p.info();
        }
    }

    (二)核心类介绍

    (1)DefaultListableBeanFactory

        XmlBeanFactory继承自DefaultListableBeanFactory,而DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载bean的默认实现,而对于XmlBeanFactory与DefaultListableBeanFactory不同的地方其实是在XmlBeanFactory中使用了自定义的XML读取器XmlBeanDefinitionReader,实现了个性化的BeanDefinitionReader读取,DefaultListableBeanFactory继承了AbstractAutowireCapableBeanFactory并实现了ConfigURableListableBeanFactory以及BeanDefinitionRegistry接口。以下是DefaultListableBeanFactory的层次结构图以下相关类图

        

    容器加载相关类图:

         

    类图中各个类的作用:

    • AliasRegistry:定义对alias的简单增删改等操作
    • SimpleAliasRegistry:主要使用map作为alias的缓存,并对接口AliasRegistry进行实现
    • SingletonBeanRegistry:定义对单例的注册及获取
    • BeanFactory:定义获取bean及bean的各种属性
    • DefaultSingletonBeanRegistry:对接口SingletonBeanRegistry各函数的实现
    • HierarchicalBeanFactory:继承BeanFactory,也就是在BeanFactory定义的功能的基础上增加了对parentFactory的支持
    • BeanDefinitionRegistry:定义对BeanDefinition的各种增删改操作
    • FactoryBeanRegistrySupport:在DefaultSingletonBeanRegistry基础上增加了对FactoryBean的特殊处理功能
    • ConfigurableBeanFactory:提供配置Factory的各种方法
    • ListableBeanFactory:根据各种条件获取bean的配置清单
    • AbstractBeanFactory:综合FactoryBeanRegistrySupport和ConfigurationBeanFactory的功能
    • AutowireCapableBeanFactory:提供创建bean、自动注入、初始化以及应用bean的后处理器
    • AbstractAutowireCapableBeanFactory:综合AbstractBeanFactory并对接口AutowireCapableBeanFactory进行实现
    • ConfigurableListableBeanFactory:BeanFactory配置清单,指定忽略类型及接口等
    • DefaultListableBeanFactory:综合上面所有功能,主要是对Bean注册后的处理

    (2)XmlBeanDefinitionReader

    XML配置文件的读取是Spring中重要的功能,因为Spring的大部分功能都是以配置作为切入点的,可以从XmlBeanDefinitionReader中梳理一下资源文件读取、解析及注册的大致脉络,首先看看各个类的功能

    • ResourceLoader:定义资源加载器,主要应用于根据给定的资源文件地址返回对应的Resource
    • BeanDefinitionReader:主要定义资源文件读取并转换为BeanDefinition的各个功能
    • EnvironmentCapable:定义获取Environment方法
    • DocumentLoader:定义从资源文件加载到转换为Document的功能
    • AbstractBeanDefinitionReader:对EnvironmentCapable、BeanDefinitionReader类定义的功能进行实现
    • BeanDefinitionDocumentReader:定义读取Document并注册BeanDefinition功能
    • BeanDefinitionParserDelegate:定义解析Element的各种方法

    整个XML配置文件读取的大致流程,在XmlBeanDefinitionReader中主要包含以下几步处理:

     

      (1)通过继承自AbstractBeanDefinitionReader中的方法,来使用ResourceLoader将资源文件路径转换为对应的Resource文件

      (2)通过DocumentLoader对Resource文件进行转换,将Resource文件转换为Document文件

      (3)通过实现接口BeanDefinitionDocumentReader的DefaultBeanDefinitionDocumentReader类对Document进行解析,并使用BeanDefinitionParserDelegate对Element进行解析

    (三)容器的基础XmlBeanFactory

    BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

    通过XmlBeanFactory初始化时序图看一看上面代码的执行逻辑

      

        首先调用ClassPathResource的构造函数来构造Resource资源文件的实例对象,这样后续的资源处理就可以用Resource提供的各种服务来操作了。

    配置文件封装

        Spring的配置文件读取是通过ClassPathResource进行封装的,Spring对其内部使用到的资源实现了自己的抽象结构:Resource接口来封装底层资源

    public interface InputStreamSource {
    
        /**
         * Return an {@link InputStream} for the content of an underlying resource.
         * <p>It is expected that each call creates a <i>fresh</i> stream.
         * <p>This requirement is particularly important when you consider an API such
         * as JavaMail, which needs to be able to read the stream multiple times when
         * creating mail attachments. For such a use case, it is <i>required</i>
         * that each {@code getInputStream()} call returns a fresh stream.
         * @return the input stream for the underlying resource (must not be {@code null})
         * @throws java.io.FileNotFoundException if the underlying resource doesn't exist
         * @throws IOException if the content stream could not be opened
         */
        InputStream getInputStream() throws IOException;
    
    }
    public interface Resource extends InputStreamSource {
    
        /**
         * Determine whether this resource actually exists in physical form.
         * <p>This method performs a definitive existence check, whereas the
         * existence of a {@code Resource} handle only guarantees a valid
         * descriptor handle.
         */
        boolean exists();
    
        /**
         * Indicate whether the contents of this resource can be read via
         * {@link #getInputStream()}.
         * <p>Will be {@code true} for typical resource descriptors;
         * note that actual content reading may still fail when attempted.
         * However, a value of {@code false} is a definitive indication
         * that the resource content cannot be read.
         * @see #getInputStream()
         */
        boolean isReadable();
    
        /**
         * Indicate whether this resource represents a handle with an open stream.
         * If {@code true}, the InputStream cannot be read multiple times,
         * and must be read and closed to avoid resource leaks.
         * <p>Will be {@code false} for typical resource descriptors.
         */
        boolean isOpen();
    
        /**
         * Return a URL handle for this resource.
         * @throws IOException if the resource cannot be resolved as URL,
         * i.e. if the resource is not available as descriptor
         */
        URL getURL() throws IOException;
    
        /**
         * Return a URI handle for this resource.
         * @throws IOException if the resource cannot be resolved as URI,
         * i.e. if the resource is not available as descriptor
         * @since 2.5
         */
        URI getURI() throws IOException;
    
        /**
         * Return a File handle for this resource.
         * @throws java.io.FileNotFoundException if the resource cannot be resolved as
         * absolute file path, i.e. if the resource is not available in a file system
         * @throws IOException in case of general resolution/reading failures
         * @see #getInputStream()
         */
        File getFile() throws IOException;
    
        /**
         * Determine the content length for this resource.
         * @throws IOException if the resource cannot be resolved
         * (in the file system or as some other known physical resource type)
         */
        long contentLength() throws IOException;
    
        /**
         * Determine the last-modified timestamp for this resource.
         * @throws IOException if the resource cannot be resolved
         * (in the file system or as some other known physical resource type)
         */
        long lastModified() throws IOException;
    
        /**
         * Create a resource relative to this resource.
         * @param relativePath the relative path (relative to this resource)
         * @return the resource handle for the relative resource
         * @throws IOException if the relative resource cannot be determined
         */
        Resource createRelative(String relativePath) throws IOException;
    
        /**
         * Determine a filename for this resource, i.e. typically the last
         * part of the path: for example, "myfile.txt".
         * <p>Returns {@code null} if this type of resource does not
         * have a filename.
         */
        String getFilename();
    
        /**
         * Return a description for this resource,
         * to be used for error output when working with the resource.
         * <p>Implementations are also encouraged to return this value
         * from their {@code toString} method.
         * @see Object#toString()
         */
        String getDescription();
    
    }

        

        InputStreamSource封装任何能返回InputStream的类,比如File、Classpath下的资源和Byte Array等, 它只有一个方法定义:getInputStream(),该方法返回一个新的InputStream对象

        Resource接口抽象了所有Spring内部使用到的底层资源:File、URL、Classpath等。首先,它定义了3个判断当前资源状态的方法:存在性(exists)、可读性(isReadable)、是否处于打开状态(isOpen)。另外,Resource接口还提供了不同资源到URL、URI、File类型的转换,以及获取lastModified属性、文件名(不带路径信息的文件名,getFilename())的方法,为了便于操作,Resource还提供了基于当前资源创建一个相对资源的方法:createRelative(),还提供了getDescription()方法用于在错误处理中的打印信息

    对不同来源的资源文件都有相应的Resource实现:文件(FileSystemResource)、Classpath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等,相关类图如下所示:

                        

    (1)配置文件封装

    public ClassPathResource(String path) {
            this(path, (ClassLoader) null);
        }
    
    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());
        }

    (2)XmlBeanFactory

    public class XmlBeanFactory extends DefaultListableBeanFactory {
    
        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);
        }
    
    
    
    /**
         * 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);
        }
    }

    (3)XmlBeanDefinitionReader 

    /**
     * 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}.
         * <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}
         * 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}
         * 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
         */
        @Override
        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} 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
         * @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);
            }
        }
    
        /**
         * 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());
        }
    
    
        /**
         * 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);
            }
        }
    
        /**
         * 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 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.
         */
        public XmlReaderContext createReaderContext(Resource resource) {
            return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
                    this.sourceExtractor, this, getNamespaceHandlerResolver());
        }
    
        /**
         * Lazily create a default NamespaceHandlerResolver, if not set before.
         * @see #createDefaultNamespaceHandlerResolver()
         */
        public NamespaceHandlerResolver getNamespaceHandlerResolver() {
            if (this.namespaceHandlerResolver == null) {
                this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
            }
            return 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());
        }
    
    }
    EncodedResource
    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;
        }
  • 相关阅读:
    HDU 4031 Attack(离线+线段树)(The 36th ACM/ICPC Asia Regional Chengdu Site —— Online Contest)
    BZOJ 1010 玩具装箱toy(四边形不等式优化DP)(HNOI 2008)
    分布式事务二阶提交DTS系统
    flume原理及代码实现
    Liferay JSP Tag Libraries介绍
    如何用maven tycho构建自己的Eclipse RCP应用
    如何合并两个git commit
    推荐一个好用的git图形化工具
    git gc干了啥
    如何把VS Code的Language Server Protocol整合到Eclipse中来
  • 原文地址:https://www.cnblogs.com/fdzfd/p/8371404.html
Copyright © 2011-2022 走看看