如何确定正在使用的 JAXP 实现以及从何处加载?

2022-09-01 03:37:04

我想提供有关正在使用的 JAXP 实现以及从哪个 JAR 文件加载它的诊断信息。

实现此目的的一种方法是在实例中创建,例如,a ,然后检查该类的属性: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 工厂实现,因为选择实现的过程。

来自 JAXP 官方常见问题解答(问题 14):

当应用程序想要创建新的 JAXP 实例时,它会调用 staic 方法 。这将导致使用以下顺序搜索具体子类的名称:DocumentBuilderFactoryDocumentBuilderFactory.newInstance()DocumentBuilderFactory

  1. 系统属性的值,例如它是否存在且可访问。javax.xml.parsers.DocumentBuilderFactory
  2. 文件的内容(如果存在)。$JAVA_HOME/jre/lib/jaxp.properties
  3. Jar 文件规范中指定的 Jar Service Provider 发现机制。jar 文件可以有一个资源(即嵌入文件),例如包含要实例化的具体类的名称。META-INF/services/javax.xml.parsers.DocumentBuilderFactory
  4. 回退平台默认实现。

除了这种复杂性之外,每个单独的 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


推荐