Инвентаризация SpringIOC: система ресурсов и документов

Java
Инвентаризация SpringIOC: система ресурсов и документов

Общая документация:Каталог статей
Github : github.com/black-ant

Введение

Вторая статья IOC все еще выбирает мягкую хурму, В этой статье говорится о методе загрузки ресурсов и документов, который также относительно прост.

Система сканирующей части включает несколько частей Resource , Document , Annotation , здесь упомянуты только первые две

2. Статьи системы ресурсов

Ресурс - это основа всего. Все внешние объекты можно рассматривать как Ресурс. По этой причине Spring предоставляет множество классов реализации Ресурса:

Resource.png

Common Resource в основном используется для следующих функций:

// 当用不同的 ResourceLoader 加载资源的时候 , 会根据资源类型的不同 , 选择生成不同的 Resource

C- ByteArrayResource : 给定字节数组的资源实现 , 用于从任何给定的字节数组加载内容,而不必求助于单一使用的InputStreamResource
C- ClassPathResource : 类路径资源的资源实现 , 使用给定的ClassLoader或给定的Class来加载资源
C- ContextResource : 用于从封闭的“上下文”加载资源的扩展接口
C- DescriptiveResource : 保存资源描述但不指向实际可读资源的简单资源实现
C- EncodedResource : 将资源描述符与用于从资源中读取的特定编码或字符集组合在一起
C- FileSystemResource : 资源实现处理一个文件系统目标
C- FileUrlResource : 它假定文件解析,达到实现WritableResource接口的程度
C- HttpResource : 将资源写入HTTP响应的扩展接口
C- ImportResource : 指示一个或多个包含要导入的bean定义的资源
C- InputStreamResource : 给定InputStream的资源实现 , 只在没有其他特定资源实现适用的情况下使用
C- ServletContextResource : ServletContext资源的资源实现,解释web应用程序根目录中的相对路径
C- VfsResource : 基于JBoss VFS的资源实现
C- WritableResource : 支持向资源写入的资源的扩展接口。提供一个输出流访问器

Функция системы ресурсов:

// 统一资源的核心类是 : Resource , 为 Spring 框架所有资源的抽象和访问接口 
I- Resource
    E- InputStreamSource

C- AbstractResource
    I- Resource
    
> 以上是统一资源管理中核心的三个类 ,他们的继承关系如上
    : Spring 中所有的资源都可以用 Resource 表示
    : AbstractResource 继承自 Resource ,并且对其做了实现
	
> Resource 中有很多常见的功能
    exists / isReadable / isOpen / isFile / getURL / getFile / readableChannel 
    contentLength / lastModified / createRelative / getFileName / getDescription
	
> AbstractResource 有以下通用的实现 
    - FileSystemResource : 对 java.io.File 类型资源的封装,只要是跟 File 打交道的,基本上与 FileSystemResource 也可以打交道
        - 支持文件和 URL 的形式,实现 WritableResource 接口,从 Spring Framework 5.0 开始,FileSystemResource 使用 NIO2 API进行读/写交互
    - ByteArrayResource : 对字节数组提供的数据的封装。
    - URIResource : 对 java.net.URL类型资源的封装。内部委派 URL 进行具体的资源操作。
    - ClassPathResource : class path 类型资源的实现。使用给定的 ClassLoader 或者给定的 Class 来加载资源。
    - InputStreamResource : 将给定的 InputStream 作为一种资源的 Resource 的实现类。
    
C- AbstractResource
    - exists() : 判断文件是否存在
    

Реализация Ресурсного интерфейса


C- AbstractResource 
    TODO
    

Ресурс будет загружаться через ResourceLoader, важный ResourceLoader содержит следующую структуру:

ResourceLoader.png

Следует отметить, что: ApplicationContext — это в основном класс реализации ResourceLoader, поэтому они обычно имеют функцию ResourceLoader.

Система загрузки ResourceLoader


> Spring 通过 ResourceLoader 来进行 资源的加载

C11- ResourceLoader : 资源的加载
    M- getResource() : 根据所提供资源的路径 location 返回 Resource 实例
        - 支持 URL位置资源 / ClassPath位置资源 / 相对路径资源
    M- getClassLoader() : 返回 ClassLoader 实例
    MC- ResourceLoader(ClassLoader)
         - Thread.currentThread().getContextClassLoader()
         - ClassUtils.getDefaultClassLoader()
         - setClassLoader()


    : interface ResourcePatternResolver extends ResourceLoader
    
C18- DefaultResourceLoader
    MC- DefaultResourceLoader
        - ClassUtils.getDefaultClassLoader();
    MC- DefaultResourceLoader(@Nullable ClassLoader classLoader)
    M- addProtocolResolver(ProtocolResolver) : 自定义的 Resolver 加入 Spring 体系
    M- getResource(String location)
        - 首先,通过 ProtocolResolver 来加载资源 , 成功返回 Resource 
        - 其次,以 / 开头,调用 #getResourceByPath() 方法, 返回 ClassPathContextResource 类型的资源
        - 再次,以 classpath: 开头,返回 ClassPathResource 类型的资源
            - 通过#getClassLoader() 获取当前的 ClassLoader
        - 然后,根据是否为文件 URL ,是则返回 FileUrlResource 类型的资源,否则返回 UrlResource 类型的资源
            - 最后,返回 ClassPathContextResource 类型的资源
            
// resourceLoader.getResource("D:/Users/chenming673/Documents/spark.txt");
    
C- ResourcePatternResolver : ResourceLoader 的默认实现
    M- setClassLoader / getClassLoader

> FileSystemResourceLoader
    内部类 : FileSystemContextResource extends FileSystemResource

C- ProtocolResolver : 用户自定义协议资源解决策略
    ?- 作为 DefaultResourceLoader 的 SPI:它允许用户自定义资源加载协议,而不需要继承 ResourceLoader 的子类
    ?- 现 ProtocolResolver 接口也可以实现自定义的 ResourceLoader
    M-  resolve(String , ResourceLoader )

Основные классы, участвующие в процессе загрузки ресурсов

// XML 流程 Resource 加载 , 我们还是从 BeanDefinitionReader 开始看起
C160- AbstractBeanDefinitionReader
	M- loadBeanDefinitions(location, null) 
	M- loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)
    	- getResourceLoader 获取一个 ResourceLoader
    	- ResourceLoader 通过 location 获取 Resource[] -> 
    	- 讲获取的  Resource 加入 actualResources , 用于后方处理
    
C16- ResourcePatternResolver 
    
    
C51- GenericApplicationContext
    M51_033- getResources(String locationPattern)
    
    
C17- PathMatchingResourcePatternResolver
    M17_02- getResources(String locationPattern)
    	- classpath*: 开头 , 则分别调用 findPathMatchingResources (-> ) / findAllClassPathResources
    	- getResourceLoader() 调用获取 Resource -> M18_05
    M17_03- findPathMatchingResources
    	- 获取路径 ,递归获取包路径
        - 通过包 URLResource 调用 doFindPathMatchingFileResources 获取类
        
    M17_04- findAllClassPathResources
    	- 调用 doFindAllClassPathResources 获取 classResource
        
    M17_05- doFindAllClassPathResources
        - 获取一个 ClassLoader , 通过 ClassLoader 获取 resource url
        - 通过 convertClassLoaderURL 对 URL 列表转换为 UrlResource
            ?- 这里其实还是包路径 -> PS:M17_05_01 
            
        
        
// PS:M17_05_01 
file:/D:/java/workspace/git/case/case%20Origin%20Source/case%20SpringBootIOC/target/classes/com/gang/study/source/springboot/demo/
        
    
C18- DefaultResourceLoader
	M18_05- getResource(String location)
         - 如果存在 ProtocolResolvers 集合, 则循环集合 , 试图用 ProtocolResolver 处理返回
		- 如果是 / 开头 , 则生成一个 ClassPathContextResource
		- 如果是 classpath 打头 ,new 创建出一个 ClassPathResource , 并且为其配置一个 ClassLoader
            	?- 所以 , 这里 bean.xml 是被映射为 ClassPathResource
		- 如果是 URL 类型 , 构建为一个 FileUrlResource
            
            
// M17_03 伪代码
// locationPattern -- classpath*:com/gang/study/source/springboot/demo/**/*.class
protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
    // classpath*:com/gang/study/source/springboot/demo/
    String rootDirPath = determineRootDir(locationPattern);
    // **/*.class
    String subPattern = locationPattern.substring(rootDirPath.length());
    
    // 扫描路径 , 将路径下资源转换为Resource数组
    Resource[] rootDirResources = getResources(rootDirPath);
    Set<Resource> result = new LinkedHashSet<>(16);
    for (Resource rootDirResource : rootDirResources) {
        rootDirResource = resolveRootDirResource(rootDirResource);
        URL rootDirUrl = rootDirResource.getURL();
        if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
            URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
            if (resolvedUrl != null) {
                rootDirUrl = resolvedUrl;
            }
            rootDirResource = new UrlResource(rootDirUrl);
        }
        if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
            // VFS 的加载方式
            result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
        }else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
            // JAR 包路径的加载
            result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
        }else {
            // 加载类
            result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
        }
    }
    return result.toArray(new Resource[0]);
}
            

Несколько сценариев загрузки Ресурса, которые обычно можно увидеть по локации

Тип 1: classpath*:com/gang/study/source/springboot/demo/**/*.class

//这种路径 , 其源头为  ComponentScanAnnotationParser 开始 , 更早的源头是 Configuration 的相关扫描逻辑

C153- ComponentScanAnnotationParser
    M153_01- parse : 由该方法扫描处理 ComponentScan  -> M155_03
        
C155- ClassPathBeanDefinitionScanner 
    M155_03- doScan(String... basePackages) -> M201_03
        
C201- ClassPathScanningCandidateComponentProvider
    M201_03- scanCandidateComponents(String basePackage)
        - 构建一个地址 -> PS:201_03_01
        - 调用 ResourcePatternResolver(AnnotationConfigServletWebServerApplicationContext) 获取 Resouce
            - 最终调用 M17_02
        
C17- PathMatchingResourcePatternResolver
    M17_02- getResources(String locationPattern) 
        - Class 前缀 , 最终调用 M17_03
    M17_03- findPathMatchingResources
    M17_04- findAllClassPathResources
        
        
        
// M201_03 伪代码
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
       //...................
    	String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
        	resolveBasePackage(basePackage) + '/' + this.resourcePattern;
       // PS:201_03_01
       // com.gang.study.source.springboot.demo 转变为
       // classpath*:com/gang/study/source/springboot/demo/**/*.class
    	Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        //...................
        
            
}


Загрузка пре-ресурсов:

M153_01M155_03M201_03M17_02ComponentScan сканирует путь к классампуть сканирования doScanВызовите PathMatchingResourcePatternResolverполучить ресурсM153_01M155_03M201_03M17_02

Загрузка Ресурсных ресурсов:

  • M17_02 : getResources
  • M17_03 : findPathMatchingResources
  • M17_04 : findAllClassPathResources
  • M17_05 : doFindAllClassPathResources
M17_02M17_03M17_04M17_05Обнаружено, что ресурс classpath для сопоставлениявызов findPathMatchingResourcesРекурсивный ресурсОбратный вызовнайден как classPathвызов findAllClassPathResourcesВозвращает конкретный classPath, то есть URLReource (фактический)Вызов загрузчика классов для сканирования определенных объектов классавернуть объект, положить в коллекциюM17_02M17_03M17_04M17_05

Основная логика такова:

  • Если путь должен быть сопоставлен: findPathMatchingResources
  • Среди них, сопоставив, вызовите findAllClassPathResources, чтобы получить реальный путь
  • По реальному пути вызовите doFindAllClassPathResources, чтобы получить конкретный ресурс класса

Тип 2: путь к классам*: загрузка ресурса messages.properties

Загрузка пре-ресурсов:


// 这种情况的加载主要来源于 Configuration , 例如 MessageSourceAutoConfiguration
// 此处对 message 资源进行加载 , 调用 ResourceBundleCondition 进行资源加载


C202- ResourceBundleCondition
    M202_01- getMatchOutcomeForBasename
        
    M202_02- getResources
        - 通过一个 classLoader 构建了一个 PathMatchingResourcePatternResolver 
        - 调用 getResources 返回相关的 resource 资源
            ?- 这里因为需要指定的资源 , 所以方式是定下了的
        
// M202_02 伪代码
private Resource[] getResources(ClassLoader classLoader, String name) {
    String target = name.replace('.', '/');
    return new PathMatchingResourcePatternResolver(classLoader).getResources("classpath*:" + target + ".properties");
			
}

// 同样的 , 调用了 PathMatchingResourcePatternResolver
// 此处无需匹配 , 直接 调用 findAllClassPathResources
C17- PathMatchingResourcePatternResolver
    M17_02- getResources(String locationPattern) 
        - 无需匹配 , 直接 调用 findAllClassPathResources ->  M17_04
    M17_04- findAllClassPathResources
   

M202_02M17_02M17_04получить путь к классам*:messages.propertiesНе нужно сопоставлять, просто вызовите findAllClassPathResources напрямуюВозвращает ресурс для URLResourceКонфигурация с использованием ресурсовM202_02M17_02M17_04

Тип 3: ресурс типа xml

Возьмем classpath:spring-common.xml в качестве примера.



// 起源 : 
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    ?- 即 ImportedResources 注解导致

// 流程 : 
C160- AbstractBeanDefinitionReader
    M- loadBeanDefinitions
        - ((ResourcePatternResolver) resourceLoader).getResources(location)
            ?- 注意 , 这里的 Resources 仍然是 pring-common.xml 这个对象

// 后续继续调用 XmlBeanDefinitionReader , 这里就不详细说了

PS: Что касается других, которые не являются репрезентативными, я не буду вдаваться в подробности.

3. Система документов

При загрузке юниформ-ресурса тип xml в нем будет обрабатываться как объект Document

Сканирование документов относится к сканированию системы документов, которое в основном используется при настройке бинов в xml.

PS: Скажу вам, в первые дни я тоже думал, что конфигурация XML устарела и устаревший метод, но теперь у меня другое ощущение, по сравнению с методом конфигурации, его структура более понятна и он не сложен в использовании .

Функция системы документов

Давайте взглянем на общие функции методов Doument:

эффект: используется для обработки объектов типа документа Document, включая .xml, .dto, .schemas и т. д.

источник: Метод XmlBeanDefinitionReader#doLoadDocument(InputSource inputSource, Resource resource)

  • Этот метод делает 2 вещи
    • Вызовите метод #getValidationModeForResource(ресурс ресурса), чтобы получить режим проверки указанного ресурса (xml).
    • Вызовите DocumentLoader#loadDocument, чтобы получить экземпляр XML-документа.
C25- DocumentLoader : 获取 Document 的策略,由接口 org.springframework.beans.factory.xml.DocumentLoader 定义
    P- inputSource 方法参数,加载 Document 的 Resource 资源。
    P- entityResolver 方法参数,解析文件的解析器。
    P- errorHandler 方法参数,处理加载 Document 对象的过程的错误。
    P- validationMode 方法参数,验证模式。
    P- namespaceAware 方法参数,命名空间支持。如果要提供对 XML 名称空间的支持,则需要值为 true 。

C26- DefaultDocumentLoader : DocumentLoader 的默认实现类 
    M26_01- loadDocument
        - 首先,调用 #createDocumentBuilderFactory(...) 方法,创建 javax.xml.parsers.DocumentBuilderFactory 对象
            - DocumentBuilderFactory.newInstance(); -- 创建 DocumentBuilderFactory
            - factory.setNamespaceAware(namespaceAware);  --  设置命名空间支持
        - 调用 #createDocumentBuilder 方法,创建 javax.xml.parsers.DocumentBuilder 对象
            - 创建 DocumentBuilder 对象
            - 设置 EntityResolver 属性
            - 设置 ErrorHandler 属性
        - 调用 DocumentBuilder#parse(InputSource) 方法,解析 InputSource ,返回 Document 对象
 
// XmlBeanDefinitionReader :     
    M- getEntityResolver() : 返回指定的解析器,如果没有指定,则构造一个未指定的默认解析器
        -1 ResourceLoader resourceLoader = getResourceLoader();
        IF-2 resourceLoader != null 
            - this.entityResolver = new ResourceEntityResolver(resourceLoader);
        ELSE-2 
            - this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());

Отслеживание сканирования документов:


// 起点 : Document 的起点是 , 这里会通过一个 Resource 加载对于的 xml , 将 XML 转换为 Document
C- ConfigurationClassBeanDefinitionReader
    M- loadBeanDefinitionsFromImportedResources 

// 中间的逻辑比较简单 , 我们直接从 XmlBeanDefinitionReader 开始看
    
C21- XmlBeanDefinitionReader
    M21_01- doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        - 调用 doLoadDocument  , 将  Resource 转换为 Document -> M23_01
        - 调用 registerBeanDefinitions(doc, resource) 注册Bean
    M21_02- doLoadDocument
        - documentLoader.loadDocument : loader 加载
    

C- DocumentLoader

C23- DefaultDocumentLoader
    I- DocumentLoader
    M23_01- loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
        - createDocumentBuilderFactory 创建一个 DocumentBuilderFactory -> M23_02
        - 通过 DocumentBuilderFactory 创建一个 DocumentBuilder -> M23_03
        - DocumentBuilder parse 方法解读 Document
    M23_02- createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
        - 通过 newInstance 生成 DocumentBuilderFactory 
        - 为 DocumentBuilderFactory 设置 NamespaceAware , Validating , 以及 Attribute
            ?- 注意 , 这里会判断 validationMode 类型来设置
    M23_03- createDocumentBuilder(DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler)
        - 通过传入的工厂生成 DocumentBuilder
        - 为 DocumentBuilder 设置 EntityResolver 和 ErrorHandler
    
    
// M23_01 补充
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
    DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    return builder.parse(inputSource);
}


// M23_02 补充
protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware){
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(namespaceAware);
    if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
        factory.setValidating(true);
        if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
            factory.setNamespaceAware(true);
            factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
            //.... 省略catch
        }
    }
    return factory;
}


// N23_03
protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory,
            @Nullable EntityResolver entityResolver, @Nullable ErrorHandler errorHandler)
            throws ParserConfigurationException {

        DocumentBuilder docBuilder = factory.newDocumentBuilder();
        if (entityResolver != null) {
            docBuilder.setEntityResolver(entityResolver);
        }
        if (errorHandler != null) {
            docBuilder.setErrorHandler(errorHandler);
        }
        return docBuilder;
}  
    

DocumentBuilder

DocumentBuilder 是一个抽象类 , 其主要 实现是 DocumentBuilderImpl


C24- DocumentBuilder
    F- DOMParser domParser;
    F- EntityResolver fInitEntityResolver
    F- ErrorHandler fInitErrorHandler
    MC- DocumentBuilderImpl
    M24_01- parse
        - domParser.parse(is) 
        - domParser getDocument 获得 Document
        
// 这里涉及到 com.sun.org.apache.xerces.internal.parsers.DOMParser 对象
C- DOMParser
    ?- 用于对 DOM 类型解析处理

Полная блок-схема обработки документов

// Step 1 : ConfigurationClassBeanDefinitionReader # loadBeanDefinitions
    ?- 用于加载 class类上面的 classpath load
// Step 2 : AbstractBeanDefinitionReader # loadBeanDefinitions
    ?- 开始加载 xml 文件
// Step 3 : XmlBeanDefinitionReader # loadBeanDefinitions
    ?- 处理加载的 resource 对象 , xml resource 的加载可以看上文
    
// Step 4 : 主要处理流程开始
C21- XmlBeanDefinitionReader
    M21_01- doLoadBeanDefinitions
        - doLoadDocument(inputSource, resource) -> M21_02
    M21_02- doLoadDocument
    
    
C26- DefaultDocumentLoader : DocumentLoader 的默认实现类 
    M26_01- loadDocument
    
C24- DocumentBuilder
      M24_01- parse


M21_01M21_02M26_01M24_01Загрузите bean.xml, получите файл ресурсов объектаdoLoadDocument обрабатывает объекты ресурсовDocumentBuilderFactory -> DocumentBuilderзагрузить документРазобрать документВернуть объект документаОбработать объект документа -> registerBeanDefinitionsM21_01M21_02M26_01M24_01

Расширить объект EntityResolver

Объект EntityResolver используется для анализа документа, и это общие:

Справочная документация @cmsblogs.com/?p=2695

  • ResourceEntityResolver: наследуется от EntityResolver и разрешает ссылки на сущности через ResourceLoader.
  • DelegatingEntityResolver: реализация EntityResolver, которая соответственно прокси-сервер BeansDtdResolver для dtd и PluggableSchemaResolver для схем xml.
  • BeansDtdResolver : Преобразователь dtd компонента Spring. Реализация EntityResolver для загрузки dtd из пути к классам или файла jar.
  • PluggableSchemaResolver: разрешает URL-адреса схемы в локальные ресурсы пути к классам, используя последовательность файлов карты.
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;
}

Дополнительные функции документа

Документ в основном предназначен для интерпретации XML как читаемых объектов.

Document.png

Дополнение DTD и XSD

Справочная документация @cmsblogs.com/?p=2688, рекомендуется посмотреть оригинальную версию, вот несколько ключевых ссылок

DTD(Document Type Definition), определение типа документа, представляет собой механизм проверки XML-файлов и является частью XML-файла.

DTD — это эффективный способ проверки правильно сформированного XML-документа, который определяет элементы, атрибуты, расположение, тип содержимого элементов и иерархическую структуру связанных XML-документов.Фактически DTD эквивалентен «словарному запасу» и «грамматике» в XML., мы можем сравнить файл XML с файлом DTD, чтобы увидеть, соответствует ли документ спецификации и правильно ли используются элементы и теги. Чтобы использовать DTD в Spring, вам нужно объявить в заголовке XML-файла Spring:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN"  "http://www.springframework.org/dtd/spring-beans.dtd">

DTD способствовал развитию XML на определенном этапе, но у него есть некоторые недостатки:

  • Он не использует формат XML, а сам определяет набор форматов, который менее пригоден для повторного использования, чем синтаксический анализатор;
  • Не существует стандартного интерфейса программирования для создания и доступа к DTD, что затрудняет простой анализ документов DTD парсерами.
  • DTD имеют меньше ограничений на тип элементов, другие ограничения также называются слабыми.
  • DTD имеет плохую масштабируемость.
  • Документы DTD на основе регулярных выражений имеют ограниченные описательные возможности.

XSD имеет следующие преимуществаВ ответ на дефекты DTD W3C представил XSD в 2001 году. XSD (определение схем XML) — это язык схем XML. XML-схема сама по себе является документом XML и использует синтаксис XML, поэтому она может легко анализировать документы XSD.

  • XML-схема основана на XML и не имеет специального синтаксиса.
  • XML-схему можно анализировать и обрабатывать как любой другой XML-документ.
  • XML-схема предоставляет более богатые типы данных, чем DTD.
  • XML-схема обеспечивает расширяемую модель данных.
  • XML-схема поддерживает комплексные пространства имен
  • XML-схема поддерживает группы атрибутов.

Различные режимы проверки анализируются с использованием разных парсеров:

Место проверки для ValidationMode


C21- XmlBeanDefinitionReader
    M21_02- doLoadDocument -> PS:M21_02_01
    
// PS:M21_02_01 此处获取了 ValidationMode
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,getValidationModeForResource(resource), isNamespaceAware());


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;
}


// 常量
/**
* 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;


Суммировать

Сканирование и сбор ресурсов и документов является основой всего.Когда они полностью собраны, можно начать загрузку связанных классов.