如何通过Java的XMLInputFactory.newInstance方法获取StAX解析器工厂实例?
- 内容介绍
- 相关推荐
本文共计878个文字,预计阅读时间需要4分钟。
基本原因并非代码编写错误,而是JVM启动时未找到符合规范要求的StAX实现类。JDK自带的`com.sun.xml.internal.stream.XMLInputFactoryImpl`在Java 9及以后版本默认不可见,且许多第三方库(如Woodstox、Aalto)的SPI配置未正确加载。
常见错误现象:javax.xml.stream.FactoryConfigurationError: Provider com.sun.xml.internal.stream.XMLInputFactoryImpl not found 或直接 fallback 到空实现导致解析失败。
- 检查 classpath 是否真有 StAX 实现 jar(如
woodstox-core-asl-4.4.1.jar),光有stax-api接口包不够 - Java 9+ 必须显式加
--add-modules java.xml.bind(仅限早期迁移),更稳妥的是用ServiceLoader.load(XMLInputFactory.class)替代静态工厂方法 - 避免依赖
com.sun.*内部类——它们不是公共 API,不同 JDK 版本路径可能变化甚至被移除
如何安全获取线程安全的 XMLInputFactory 实例
XMLInputFactory 本身是线程安全的,但它的实例不建议全局单例复用,因为部分实现(如 Woodstox)会在实例上缓存配置状态,多线程修改 setProperty() 可能互相干扰。
推荐做法是每个解析上下文创建独立实例,并统一配置关键参数:
立即学习“Java免费学习笔记(深入)”;
- 设
factory.setProperty(<code>javax.xml.stream.isNamespaceAware, Boolean.TRUE),否则默认不识别命名空间 - 禁用 DTD(防止 XXE):
factory.setProperty(<code>javax.xml.stream.isSupportingExternalEntities, Boolean.FALSE) - 若需读取注释,必须提前设
factory.setProperty(<code>javax.xml.stream.isCoalescing, Boolean.TRUE),否则nextTag()可能跳过注释
对比 newInstance() 和 newFactory() 的行为差异
JDK 6 引入了 XMLInputFactory.newFactory(),它比 newInstance() 更严格:前者只走标准 SPI 查找(META-INF/services/javax.xml.stream.XMLInputFactory),后者还会尝试硬编码 fallback 到 Sun 内部实现。
这意味着:
- 用
newFactory()能更快暴露缺失实现的问题,适合构建环境验证 - 在 Android 或某些精简 JRE 上,
newInstance()可能静默返回一个功能受限的空实现,而newFactory()直接抛异常 - 两者都支持传入
ClassLoader参数,但只有显式传入非null的 classloader 才能绕过模块系统限制(Java 9+)
Woodstox 下 XMLInputFactory 的典型初始化陷阱
Woodstox 是最常用的高性能 StAX 实现,但它不兼容 JDK 自带工厂的某些默认行为。比如默认关闭 CDATA 事件,或对空白字符处理更严格。
容易踩的坑:
- 没调用
WoodstoxInputFactory.setProperty(<code>org.codehaus.stax2.validation.XMLValidationSchema, schema) 就想做 XSD 校验 → 直接忽略校验逻辑 - 用
XMLInputFactory.newInstance()获取到的是 JDK 默认实现,不是 Woodstox —— 必须确保woodstox-core-asl在 classpath 且META-INF/services/...文件存在 - 设置
javax.xml.stream.isReplacingEntityReferences为false后,仍看到实体被展开 → Woodstox 默认忽略该属性,得用org.codehaus.stax2.typed.TypedXMLStreamReader手动控制
XMLInputFactory.newInstance() 行为最隐蔽的两个变量,调试时优先检查这两点,而不是怀疑 XML 内容本身。本文共计878个文字,预计阅读时间需要4分钟。
基本原因并非代码编写错误,而是JVM启动时未找到符合规范要求的StAX实现类。JDK自带的`com.sun.xml.internal.stream.XMLInputFactoryImpl`在Java 9及以后版本默认不可见,且许多第三方库(如Woodstox、Aalto)的SPI配置未正确加载。
常见错误现象:javax.xml.stream.FactoryConfigurationError: Provider com.sun.xml.internal.stream.XMLInputFactoryImpl not found 或直接 fallback 到空实现导致解析失败。
- 检查 classpath 是否真有 StAX 实现 jar(如
woodstox-core-asl-4.4.1.jar),光有stax-api接口包不够 - Java 9+ 必须显式加
--add-modules java.xml.bind(仅限早期迁移),更稳妥的是用ServiceLoader.load(XMLInputFactory.class)替代静态工厂方法 - 避免依赖
com.sun.*内部类——它们不是公共 API,不同 JDK 版本路径可能变化甚至被移除
如何安全获取线程安全的 XMLInputFactory 实例
XMLInputFactory 本身是线程安全的,但它的实例不建议全局单例复用,因为部分实现(如 Woodstox)会在实例上缓存配置状态,多线程修改 setProperty() 可能互相干扰。
推荐做法是每个解析上下文创建独立实例,并统一配置关键参数:
立即学习“Java免费学习笔记(深入)”;
- 设
factory.setProperty(<code>javax.xml.stream.isNamespaceAware, Boolean.TRUE),否则默认不识别命名空间 - 禁用 DTD(防止 XXE):
factory.setProperty(<code>javax.xml.stream.isSupportingExternalEntities, Boolean.FALSE) - 若需读取注释,必须提前设
factory.setProperty(<code>javax.xml.stream.isCoalescing, Boolean.TRUE),否则nextTag()可能跳过注释
对比 newInstance() 和 newFactory() 的行为差异
JDK 6 引入了 XMLInputFactory.newFactory(),它比 newInstance() 更严格:前者只走标准 SPI 查找(META-INF/services/javax.xml.stream.XMLInputFactory),后者还会尝试硬编码 fallback 到 Sun 内部实现。
这意味着:
- 用
newFactory()能更快暴露缺失实现的问题,适合构建环境验证 - 在 Android 或某些精简 JRE 上,
newInstance()可能静默返回一个功能受限的空实现,而newFactory()直接抛异常 - 两者都支持传入
ClassLoader参数,但只有显式传入非null的 classloader 才能绕过模块系统限制(Java 9+)
Woodstox 下 XMLInputFactory 的典型初始化陷阱
Woodstox 是最常用的高性能 StAX 实现,但它不兼容 JDK 自带工厂的某些默认行为。比如默认关闭 CDATA 事件,或对空白字符处理更严格。
容易踩的坑:
- 没调用
WoodstoxInputFactory.setProperty(<code>org.codehaus.stax2.validation.XMLValidationSchema, schema) 就想做 XSD 校验 → 直接忽略校验逻辑 - 用
XMLInputFactory.newInstance()获取到的是 JDK 默认实现,不是 Woodstox —— 必须确保woodstox-core-asl在 classpath 且META-INF/services/...文件存在 - 设置
javax.xml.stream.isReplacingEntityReferences为false后,仍看到实体被展开 → Woodstox 默认忽略该属性,得用org.codehaus.stax2.typed.TypedXMLStreamReader手动控制
XMLInputFactory.newInstance() 行为最隐蔽的两个变量,调试时优先检查这两点,而不是怀疑 XML 内容本身。
