关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

云南大王-通俗理解spring源码(三)—— 获取xml的验证模式

发布时间:2020-04-16 00:00:00
通俗理解spring源码(三)—— 获取xml的验证模式 上一篇讲到了xmlBeanDefinitionReader.doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法。 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //从资源文件转换为document对象 Document doc = doLoadDocument(inputSource, resource); //解析document,并注册beanDefiniton到工厂中 int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } }  在该方法中,首先就是将资源文件装换为document对象 protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); }    通过getValidationModeForResource(resource)获取xml文件的验证模式。 xml文件有两种校验模式,DTD和XSD,这里简单介绍一下: 1、DTD校验模式 DTD(Document Type Definition)即文档类型定义,是一种xml约束模式语言,是xml文件的验证机制,属于xml文件的一部分。DTD是一种保证xml文档格式正确的有效方法,可以通过比较xml文档和DTD文件来看文档是否符合规范,元素和标签使用是或否正确。一个DTD文档包含:元素的定义规则,元素间关系的定义规则,元素可使用的属性,可使用的实体或符号规则。 这个DTD文件,可以直接写在xml内部,如: ]> George John Reminder Don't forget the meeting! 也可以外部引用,比如将DTD内容写在与xml文件同目录的note.dtd中,如: George John Reminder Don't forget the meeting!    还可以引用网络上的DTD文件,如在我们最熟悉的mybatis配置文件中:   引用外部DTD文件,一定会有声明!   关于DTD文档的详细语法,可以参考https://www.w3school.com.cn/dtd/index.asp。 2、XSD验证模式   XML Schema语言就是XSD(XML Schemas Definition)。XML Schema描述了xml文档的结构,可以用一个指定的XML Schema来验证某个XML文档,以检查该xml文档是否符合要求。文档设计者可以通过XML Schema指定xml文档所允许的结构和内容,并可据此检查xml文档是否是有效的。XML Schema本身是xml文档,它符合xml语法结构。可以用通用的xml‘解析器解析它。   XSD比DTD更加强大,可针对未来的需求进行扩展,基于 XML 编写,支持数据类型,支持命名空间等。   一个xml文件中可以引入多个命名空间,每个命名空间都要与一个前缀绑定,或者没有前缀,作为默认命名空间,并且每个命名空间都要指定其对应的xml Schema文件位置或URL位置,如在spring配置文件中:   其中, xmlns="http://www.springframework.org/schema/beans xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd   表示引入beans作为默认命名空间,相对应的xsd文件在http://www.springframework.org/schema/beans/spring-beans-4.3.xsd中,要使用该命名空间的标签,不用加前缀。 xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd    表示引入context命名空间,并与context前缀相绑定,相对应的xsd文件在http://www.springframework.org/schema/context/spring-context-4.3.xsd中,即要使用该命名空间的标签,需要加context前缀,比如说我们最熟悉的  。   关于XSD文档的详细语法,可以参考https://www.w3school.com.cn/schema/index.asp。  3、验证模式的读取   了解了DTD和XSD的区别后再去分析spring中对于验证模式的获取就容易多了。   接着来看getValidationModeForResource(resource)。 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; }    这里逻辑很简单,作者的注释也很有意思,就是说我们无法清楚的知道准确的验证模式,如果在找到文档的根标签之前还没有找到明显的DTD声明,则推测为XSD验证模式。   继续看一下detectValidationMode(resource)方法: 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); } }    又是委派模式,由validationModeDetector进行处理,进入validationModeDetector.detectValidationMode(inputStream)中: 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; } //判断该行是否包含DOCTYPE这个字符串 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(); } } private boolean hasDoctype(String content) { return content.contains(DOCTYPE); } private boolean hasOpeningTag(String content) { if (this.inComment) { return false; } int openTagIndex = content.indexOf('<'); return (openTagIndex > -1 && (content.length() > openTagIndex + 1) && Character.isLetter(content.charAt(openTagIndex + 1))); }   一行行读取文件内容,去掉文件的注释内容,首先判断该行是否包含DOCTYPE这个字符串,如果有则判定为VALIDATION_DTD,如果没有,再判断该行是否包含开始标签符号,如果有,则判定VALIDATION_XSD,如果没有,则读取下一行。     获取xml验证模式的逻辑并不复杂,主要是要知道DTD和XSD的区别。   走的太远,不要忘记为什么出发!获取校验模式的目的是要对xml文件进行校验,然后解析成document。 protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); }    下一章将讲解documentLoader.loadDocument,获取Document。   参考:https://www.w3school.com.cn/    https://www.cnblogs.com/osttwz/p/6892999.html    spring源码深度解析

相关阅读

云南网站建设初期应该注意哪些问题云南网站建设中原创文章对网站起什么作用Javascript中如何中断forEach循环云南零售小程序前景怎么样?如何优化WEB应用数据库访问慢的问题?Javascript中用let和var声明变量的区别是什么redis 的主从复制和哨兵?递归和迭代有何区别?<input> 标签的 readonly 属性怎么用?云南网站建设中网页版商城如何保证网站安全云南企业官网如何推广云南企业网站建设为什么把文章类型的栏目排在前面云南餐饮小程序能带给餐饮业什么?云南网站建设需要注意什么地方云南云服务器配置如何选择合适的云南网站建设和网站设计有何区别?云南网站建设—企业官网的好处在哪?云南做小程序的优势在哪?为什么建议做小程序?网站为什么要配置ssl证书?网站为什么要做seo,做seo有什么好处?微信小程序_企业付款到零钱 API 开发如何利用缓存提高asp.net网站访问速度中小型企业如何选择服务器配置?如何优化中小型企业网站C#.net做网站后台 需要记录日志基于asp.net企业门户网站设计霓裳民族服装seo优化分析建议Javascript的函数封装认识及使用Ajax请求中data与后端的交互有哪几种方法JavaScript如何实现组合模式???SQL之子查询的基本用法有哪些?什么是静态测试、动态测试、黑盒测试、白盒测试、α测试 β测试?C# 引入委托的目的是什么c# 委托的本质是什么C# DataGridView添加新行的2个方法C#支付宝扫码支付代码完整版c# MVC 微信支付教程系列之扫码支付代码实例Redis基础通用操作指令有哪些?String、StringBuffer和StringBuilder的各自用法常见的一些Dos命令有哪些?如何在C#中复制一个Windows窗体类前端js中的运算符的种类,=、==与===的有何区别?网站前端怎么设置页面禁止转载?解决XSS脚本攻击恶意代码的方法你知道?javascript 之 apply()、call() 探索net core实现跨域ASP.NET Core程序部署到LinuxASP.NET Core使用AutoMapper.NET Core:处理全局异常.NET Core在ASP.NET Core WebApi中使用CookieASP.NET Core:ASP.NET Core中使用NLog记录日志如何重启iis服务器SQL Server代理服务无法启动怎么办js 判断手机版与PC版自适应跳转升级版 PC版手机版界面对应跳转IIS服务器SSL证书安装js 判断手机版与PC版自适应跳转C#截取字符串的方法C# 中使用正则表达式验证手机号、身份证号码强制性修改div框里出现的css值VS2017调试代码显示“当前无法命中断点,还没有为该文档加载任何符号”js获取当前域名、Url、相对路径和参数以及指定参数JavaScript数组整理C# 对象和类型总结关于javascript跳转与返回和刷新页面Express中的中间件简介及用法JS的原型和继承webstorm的 Emmet 快捷方式什么是Redis缓存的雪崩、击穿、穿透Cookie的基本介绍和场景Vue.js中keep-alive缓存(页面+滚动条)HTML5在客户端是如何存储数据的?MySQL中多表操作有哪些?Cookie与Session的认识使用集合组织相关数据深入C#数据类型c#中的委托简单认识.NET框架密码学系列——常见的加密方式有哪些.NET 异步详解线程池的五种实现方式centos7系统中忘记了root管理员账号密码的解决方式公司管理必须的20条军规[参考]云南昆明天猫旗舰店如何开_怎么开_要什么条件云南大王-通俗理解spring源码(三)—— 获取xml的验证模式 云南大王-用户登录 云南大王-【Golang进阶】指针的详细讲解 云南大王-Java 单线程代码ThreadLocal串值问题 云南大王-Java 实例级别的锁和类级别的锁 云南大王-工作流引擎会签,加签,主持人,组长模式专题讲解 云南大王-Android连载5云南大王-NTP对时器(NTP对时服务器)重要性!京准电子科技 云南大王-关于redis单线程的分析 云南大王-CVE云南大王-PHP SESSION反序列化本地样例分析 云南大王-这不就是多线程ThreadPoolExecutor和阻塞队列吗 云南大王-Tomcat AJP 文件包含漏洞(CVE云南大王-讲真,这两款idea插件,能治愈你英语不好的病 云南大王-消息中间件ActiveMQ、RabbitMQ、RocketMQ、ZeroMQ、Kafka如何选型? 云南大王-JVM系列十三(类加载器). 云南大王-Win10安装MySQL8压缩包版
/template/Home/Zkeys/PC/Static