如何找出正在使用的JAXP实现以及从哪里加载?

Dan*_*nov 30 java diagnostics version jaxp

我想提供有关正在使用的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());
}
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法来实现这一点,也许无需创建DocumentBuilderFactory

Dan*_*nov 54

由于选择实现的过程很难预测在没有实际创建实例的情况下将加载哪个具体的JAXP工厂实现.

来自官方JAXP常见问题解答(问题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());
}
Run Code Online (Sandbox Code Playgroud)

以下示例输出说明了三种不同JAXP实现(Xerces 2.8和Xalan的内置Xerces和外部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
Run Code Online (Sandbox Code Playgroud)


小智 8

只需添加

-Djaxp.debug=1
Run Code Online (Sandbox Code Playgroud)

JAVA_OPTS,你会看到这样的信息.

有关更多详细信息,请访问:https://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilderFactory.html