记一次SPI机制导致的BUG定位【不支持:http://javax.xml.XMLConstants/property/accessExternalDTD】
1、前因
今天在生产环境启用了某个功能,结果发现有个文件上传华为云OBS失败了,报错如下:
Caused by: java.lang.IllegalArgumentException: 不支持:http://javax.xml.XMLConstants/property/accessExternalDTDat org.apache.xalan.processor.TransformerFactoryImpl.setAttribute(TransformerFactoryImpl.java:576) ~[xalan-2.7.1.jar:?]at com.obs.services.internal.xml.OBSXMLBuilder.asString(OBSXMLBuilder.java:306) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.internal.V2Convertor.transCompleteMultipartUpload(V2Convertor.java:96) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.internal.service.ObsMultipartObjectService.completeMultipartUploadImpl(ObsMultipartObjectService.java:96) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.AbstractMultipartObjectClient.access$400(AbstractMultipartObjectClient.java:39) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.AbstractMultipartObjectClient$5.action(AbstractMultipartObjectClient.java:185) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.AbstractMultipartObjectClient$5.action(AbstractMultipartObjectClient.java:182) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.AbstractClient.doActionWithResult(AbstractClient.java:388) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]... 50 more
2、BUG定位
首先看抛异常的第一条信息,org.apache.xalan.processor.TransformerFactoryImpl,这个类首先看名称,后面带了Impl,一般来说应该是某个接口的实现类,因为这个是引用的jar包里报的错,还是apache的jar包,一般来说不太可能是apache代码写错了,所以很有可能是我们调这个接口的时候,调错实现类了,实际上不应该调apache的这个实现类。
直接来看调用方com.obs.services.internal.xml.OBSXMLBuilder的asString方法:
public String asString() throws TransformerException {TransformerFactory tf = TransformerFactory.newInstance();tf.setAttribute("http://javax.xml.XMLConstants/property/accessExternalDTD", "");tf.setAttribute("http://javax.xml.XMLConstants/property/accessExternalStylesheet", "");Transformer transformer = tf.newTransformer();transformer.setOutputProperty("omit-xml-declaration", "yes");StringWriter writer = new StringWriter();transformer.transform(new DOMSource(this.getDocument()), new StreamResult(writer));return writer.getBuffer().toString().replaceAll("|\r", "");
}
代码里的TransformerFactory是个抽象类,整个方法中也没有指定使用到底用哪个实现类,这个时候就应该想到Java的SPI机制了,打开org.apache.xalan.processor.TransformerFactoryImpl所在Jar包,Jar包里有个文件夹META-INF,里面有个services的文件夹,这里面的文件,就指定了程序会使用TransformerFactory的哪个实现类,如下图:

打开该文件,文件内容如下:
org.apache.xalan.processor.TransformerFactoryImpl
由于我们的程序里没有相应的SPI配置,所以程序会优先使用org.apache.xalan.processor.TransformerFactoryImpl类
3、BUG修复
知道了问题所在,接下来就是要找到那个正确的类,我们进到TransformerFactory这个类里,由于我用的是IDEA,点类边上的蓝色按钮就可以找到这个类的子类,如下图:

可以看到同样叫TransformerFactoryImpl名字的,还有com.sun.org.apache.xalan.internal.xsltc.trax包下的类,然后我们就在项目的META-INF的目录下新增services目录(如果没有的话),在该目录下新增文件javax.xml.transform.TransformerFactory,如图:

文件内容如下:
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
再启动服务时,服务就正常了
4、疑惑
眼尖的小伙伴可能会发现,我这个异常是在生产环境抛出来的,难道我之前测试环境没测出来这个问题吗,是的,测试环境当时测的时候没有指定实现类也没有报错,文件也正常上传到了华为云OBS上,但是这个问题发生后,再在测试环境就没法复现这个问题了,所以也没有再深究。
找到问题了,我们在引入OBS的jar包时是这样写的:
<dependency><groupId>com.huaweicloud</groupId><artifactId>esdk-obs-java-bundle</artifactId><version>[3.21.8,)</version>
</dependency>
这种写法会导致使用最新版本的jar包,来看jar包的发布时间:

我们测试的时候大概是在十月份,十一月、十二月都有过发布,功能启用时间更是在后面,所以我们测试的jar跟生产的jar实际上版本是不一样的,生产是3.23.9.1,而测试是3.23.9,我们将版本指定为3.23.9后查看com.obs.services.internal.xml.OBSXMLBuilder源码,里面并没有使用抽象类TransformerFactory,所以也不会有上面所说的问题。
相关文章:
记一次SPI机制导致的BUG定位【不支持:http://javax.xml.XMLConstants/property/accessExternalDTD】
1、前因 今天在生产环境启用了某个功能,结果发现有个文件上传华为云OBS失败了,报错如下: Caused by: java.lang.IllegalArgumentException: 不支持:http://javax.xml.XMLConstants/property/accessExternalDTDat org.apache.xal…...
Kali如何启动SSH服务并实现无公网ip环境远程连接
文章目录 1. 启动kali ssh 服务2. kali 安装cpolar 内网穿透3. 配置kali ssh公网地址4. 远程连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 简单几步通过[cpolar 内网穿透](cpolar官网-安全的内网穿透工具 | 无需公网ip | 远程访问 | 搭建网站)软件实现ssh 远程连接kali! …...
谷粒商城配置虚拟机
一、创建虚拟机 之前有在VM里面建一个ubuntu的虚拟机,准备拿来直接用,网络设置为NAT模式,查看我的虚拟机是虚拟机:192.168.248.128 主机: 192.168.2.12。可以互相ping通。 二、linux安装docker Docker docker是虚拟…...
Java中文乱码浅析及解决方案
Java中文乱码浅析及解决方案 一、GBK和UTF-8编码方式二、idea和eclipse的默认编码方式三、解码和编码方法四、代码实现编码解码 五、额外知识扩展 一、GBK和UTF-8编码方式 如果采用的是UTF-8的编码方式,那么1个英文字母 占 1个字节,1个中文占3个字节如果…...
【前端基础--3】
文字样式 1.文字颜色 color 取值方式: 英文单词 red green blue十六进制的颜色值 #000000 也可以写为#000(如aabbcc可以简写为abc)rgb三原色取值 color:rgb(220,32,215) 取值范围都在0~255之间 2.文字大小 font-size …...
Obsidian笔记软件结合cpolar实现安卓移动端远程本地群晖WebDAV数据同步
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
51单片机电子密码锁Proteus仿真+程序+视频+报告
目录 视频 设计分析 系统结构 仿真图 资料内容 资料下载地址:51单片机电子密码锁Proteus仿真程序视频报告 视频 单片机电子密码锁Proteus仿真程序视频 设计分析 (1)能够从键盘中输入密码,并相应地在显示器上显示‘*’; (2)能够判断密码…...
[BSidesCF 2020]Had a bad day
先看url,发现可能有注入 http://655c742e-b427-485c-9e15-20a1e7ef1717.node5.buuoj.cn:81/index.php?categorywoofers 试试能不能查看index.php直接?categoryindex.php不行,试试伪协议 把.php去掉试试 base64解码 <?php$file $_GET[category];…...
[笔记]事务简介-springboot
在Spring Boot中,事务的管理通常通过注解来实现,使得配置变得简单而直观。这种方式与Spring Boot的设计理念一致,即减少显式配置,增加自动配置。以下是如何在Spring Boot项目中应用和管理事务的详细说明: Spring Boot中…...
初识计算机网络 | 计算机网络的发展 | 协议初识
1.计算机网络的发展 “矛盾是普遍存在的,矛盾是事物联系的实质内容和事物发展的根本动力!” 计算机在诞生之初,在军事上用来计算导弹的弹道轨迹!在发展的过程中(商业的推动,国家政策推动)&…...
【sgTree】自定义组件:加载el-tree树节点整棵树数据,实现增删改操作。
特性 可以自定义主键、配置选项支持预定义节点图标:folder文件夹|normal普通样式多个提示文本可以自定义支持动态接口增删改节点可以自定义根节点id可以设置最多允许添加的层级深度支持拖拽排序,排序过程还可以针对拖拽的节点深度进行自定义限制支持隐藏…...
vue2面试题:vue组件之间的通信方式有哪些?
vue2面试题:vue组件之间的通信方式有哪些? 回答思路:1.组件通信的目的-->2.组件通信的分类-->3.组件通信的方案1.组件通信的目的2.组件通信的分类3.组件通信的方案(1)通过props传递数据(2)…...
Pytorch神经网络模型nn.Sequential与nn.Linear
1、定义模型 对于标准深度学习模型,我们可以使用框架的预定义好的层。这使我们只需关注使用哪些层来构造模型,而不必关注层的实现细节。 我们首先定义一个模型变量net,它是一个Sequential类的实例。 Sequential类将多个层串联在一起。 当给…...
C++-gdb调试常用功能
文章目录 启动gdb运行程序设置断点运行控制查看源码查看信息查看变量线程相关 gdb调试常用功能如下,其中bin为要调试的程序,arg为参数 启动gdb 启动调试 gdb bin带参数启动 gdb --args bin arg1 arg2so预加载LD_PRELOAD/path/to/lib.so && gdb …...
快速上手的AI工具-文心一言辅助学习
前言 大家好晚上好,现在AI技术的发展,它已经渗透到我们生活的各个层面。对于普通人来说,理解并有效利用AI技术不仅能增强个人竞争力,还能在日常生活中带来便利。无论是提高工作效率,还是优化日常任务,AI工…...
Boost 适用 filesystem 库,statx 函数无法找到引用问题的解决方案。
1、boost 高版本使用了 statx 函数,这个函数是在 Linux 内核版本 4.11 之后引入的。 所以:可以升级 Linux 内核版本到4.11之后即可。 2、降低 boost 库版本到 1.70 以下 3、正确的路,改 boost 的编译代码 先看这个: Filesyste…...
MyBatis中一级缓存是什么?SqlSession一级缓存失效的原因?如何理解一级缓存?
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就 会从缓存中直接获取,不会从数据库重新访问 使一级缓存失效的四种情况: 1) 不同的SqlSession对应不同的一级缓存 2) 同一…...
项目解决方案:多地医馆的高清视频监控接入汇聚联网
目 录 一、背景 二、建设目标及需求 1.建设目标 2.现状分析 3.需求分析 三、方案设计 1.设计依据 2.设计原则 3.方案设计 3.1 方案描述 3.2 组网说明 四、产品介绍 1.视频监控综合资源管理平台介绍 2.视频录像服务器和存储 2.1概述 2.2存储设计 …...
【前端基础--2】
选择器优先级 style标签中: .text{color: pink;}div{color: red;}#box{color: skyblue;} body标签中: <div class"text" id"box">猜猜我是什么颜色的</div> 运行结果: 选择器优先级权重: id选…...
【GitHub项目推荐--提取文字】【转载】
提取视频中的字幕 这个开源项目是提取视频中字幕的开源项目,提取视频中的关键帧,检测视频帧中文本的所在位置,识别视频帧中文本的内容。 不知道大家有没有做笔记的习惯,这个开源项目就很方便的把你一个视频中的字幕提取出来&…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
