如何找出正在使用的 JAXP 实现以及它是从哪里加载的?
Posted
技术标签:
【中文标题】如何找出正在使用的 JAXP 实现以及它是从哪里加载的?【英文标题】:How do I find out which JAXP implementation is in use and where it was loaded from? 【发布时间】:2009-11-25 16:58:28 【问题描述】:我想提供有关正在使用的 JAXP 实现以及从哪个 JAR 文件加载它的诊断信息。
实现此目的的一种方法是创建一个实例,例如 DocumentBuilderFactory
,然后检查该类的属性:
private static String GetJaxpImplementation()
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
Class<? extends DocumentBuilderFactory> c = documentBuilderFactory.getClass();
Package p = c.getPackage();
CodeSource source = c.getProtectionDomain().getCodeSource();
return MessageFormat.format(
"Using JAXP implementation ''0'' (1) version 2 (3)4",
p.getName(),
p.getImplementationVendor(),
p.getSpecificationVersion(),
p.getImplementationVersion(),
source == null ? "." : " loaded from: " + source.getLocation());
有没有更好的方法来实现这一点,也许不必创建DocumentBuilderFactory
?
【问题讨论】:
【参考方案1】:在不实际创建实例的情况下,很难预测将加载哪些具体的 JAXP 工厂实现,因为选择实现的过程。
来自Official JAXP FAQ(问题14):
当应用程序想要创建一个 新的 JAXP
DocumentBuilderFactory
例如,它调用 staic 方法DocumentBuilderFactory.newInstance()
。 这会导致搜索名称 具体的子类DocumentBuilderFactory
使用 以下顺序:
javax.xml.parsers.DocumentBuilderFactory
等系统属性的值(如果存在且可访问)。 文件$JAVA_HOME/jre/lib/jaxp.properties
的内容(如果存在)。 Jar 文件规范中指定的 Jar 服务提供者发现机制。 jar 文件可以有一个资源(即嵌入文件),例如META-INF/services/javax.xml.parsers.DocumentBuilderFactory
,其中包含要实例化的具体类的名称。 后备平台默认实现。
除了这种复杂性之外,每个单独的 JAXP 工厂都可以指定一个独立的实现。使用一个解析器实现和另一个 XSLT 实现是很常见的,但是上面选择机制的粒度允许您在更大程度上混合和匹配。
以下代码将输出有关四个主要 JAXP 工厂的信息:
private static void OutputJaxpImplementationInfo()
System.out.println(getJaxpImplementationInfo("DocumentBuilderFactory", DocumentBuilderFactory.newInstance().getClass()));
System.out.println(getJaxpImplementationInfo("XPathFactory", XPathFactory.newInstance().getClass()));
System.out.println(getJaxpImplementationInfo("TransformerFactory", TransformerFactory.newInstance().getClass()));
System.out.println(getJaxpImplementationInfo("SAXParserFactory", SAXParserFactory.newInstance().getClass()));
private static String getJaxpImplementationInfo(String componentName, Class componentClass)
CodeSource source = componentClass.getProtectionDomain().getCodeSource();
return MessageFormat.format(
"0 implementation: 1 loaded from: 2",
componentName,
componentClass.getName(),
source == null ? "Java Runtime" : source.getLocation());
以下示例输出说明了三种不同 JAXP 实现(内置 Xerces 和 Xerces 2.8 和 Xalan 的外部 JAR)的混合搭配:
DocumentBuilderFactory implementation: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xerces-2.8.0.jar
XPathFactory implementation: com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl loaded from: Java Runtime
TransformerFactory implementation: org.apache.xalan.processor.TransformerFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xalan.jar
SAXParserFactory implementation: org.apache.xerces.jaxp.SAXParserFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xerces-2.8.0.jar
【讨论】:
【参考方案2】:只需添加
-Djaxp.debug=1
到JAVA_OPTS
,你会看到这样的信息。
更多详情:https://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilderFactory.html
【讨论】:
【参考方案3】:很简单,你只需设置
System.setProperty("jaxp.debug", "1");
曲目会告诉你 whick impl 和 jaxp 的使用方式。
【讨论】:
【参考方案4】:在“回退平台默认实现”之前搜索了另一个位置,即 java.endorsed.dirs
目录,如 Java Endorsed Standards Override Mechanism 中所述
认可的标准覆盖机制提供了一种方法,可以将实现认可标准或独立技术的类和接口的更高版本合并到 Java 平台中。
【讨论】:
从 8u40 开始 BTW 已弃用,您可以检查它是否仍在使用-XX:+CheckEndorsedAndExtDirs
。【参考方案5】:
视情况而定,但一般不会。
DocumentBuilderFactory.newInstance()
将返回在系统属性“javax.xml.parsers.DocumentBuilderFactory”中配置的DocumentBuilderFactory
的实现,或者如果系统属性未设置,则返回 JRE 的默认工厂。默认工厂很可能在 newInstance 方法的实现中被硬编码,否则无法访问。
如果设置了系统属性,你至少可以使用相关类加载器上的getResource方法来获取URL,类加载器将从该URL加载相应的类文件。如果它来自 jar 文件,您应该能够从 jar: URL 中提取文件名(或源 URL)。如果您从类路径中手动读取元数据文件,也应该可以获得详细的包信息。
如果未设置系统属性,我很确定如果没有像您已经在做的那样实际创建新工厂,您将无法获得所需的信息。
【讨论】:
以上是关于如何找出正在使用的 JAXP 实现以及它是从哪里加载的?的主要内容,如果未能解决你的问题,请参考以下文章