【问题标题】:How do I find out which JAXP implementation is in use and where it was loaded from?如何找出正在使用的 JAXP 实现以及它是从哪里加载的?
【发布时间】: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?

【问题讨论】:

    标签: java version diagnostics jaxp


    【解决方案1】:

    在不实际创建实例的情况下,很难预测将加载哪些具体的 JAXP 工厂实现,因为选择实现的过程。

    来自Official JAXP FAQ(问题14):

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

    1. javax.xml.parsers.DocumentBuilderFactory 等系统属性的值(如果存在且可访问)。
    2. 文件$JAVA_HOME/jre/lib/jaxp.properties 的内容(如果存在)。
    3. Jar 文件规范中指定的 Jar 服务提供者发现机制。 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

      【讨论】:

        【解决方案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)。如果您从类路径中手动读取元数据文件,也应该可以获得详细的包信息。

          如果未设置系统属性,我很确定如果没有像您已经在做的那样实际创建新工厂,您将无法获得所需的信息。

          【讨论】:

            猜你喜欢
            • 2020-03-19
            • 2011-07-01
            • 1970-01-01
            • 2010-10-22
            • 1970-01-01
            • 2017-10-02
            • 2012-10-22
            • 2019-01-30
            • 2013-01-29
            相关资源
            最近更新 更多