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

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

实现此目的的一种方法是在例如DocumentBuilderFactory实例中创建,然后检查该类的属性:

 private static String GetJaxpImplementation() { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); Class 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

由于选择实现的过程很难预测在没有实际创建实例的情况下将加载哪个具体的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()); } 

以下示例输出说明了三种不同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 

只需添加

 -Djaxp.debug=1 

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

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

这很简单,你只需要设置

 System.setProperty("jaxp.debug", "1"); 

赛道会告诉你whick impl,以及jaxp使用的方式。

这取决于,但通常没有。

DocumentBuilderFactory.newInstance()将返回在系统属性“javax.xml.parsers.DocumentBuilderFactory”中配置的DocumentBuilderFactory的实现,或者如果未设置系统属性,则返回JRE的默认工厂。 默认工厂很可能在newInstance方法的实现中进行硬编码,否则无法访问。

如果设置了系统属性,则至少可以在相关的类加载器上使用getResource方法来获取URL,类加载器将从该URL加载相应的类文件。 如果它来自jar文件,您应该能够从jar:URL中提取文件名(或源URL)。 如果您从类路径中手动读取元数据文件,则还应提供详细的包信息。

如果没有设置系统属性,我很确定你没有办法获得你正在寻找的信息,而没有像你现在那样实际创建一个新的工厂。

在“回退平台默认实现”之前搜索了另一个位置,这是Java认可的标准覆盖机制中记录的java.endorsed.dirs目录。

支持标准覆盖机制提供了一种方法,可以将实现认可标准或独立技术的更高版本的类和接口合并到Java平台中。