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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1798366/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 22:45:46  来源:igfitidea点击:

How do I find out which JAXP implementation is in use and where it was loaded from?

javaversiondiagnosticsjaxp

提问by Daniel Fortunov

I would like to provide diagnostic information about what JAXP implementation is in use, and which JAR file it was loaded from.

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

One way to achieve this is to create in instance of, for example, a DocumentBuilderFactory, and then inspect the properties of that class:

实现此目的的一种方法是创建一个实例,例如 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());
}

Is there a better way to achieve this, perhaps without having to create a DocumentBuilderFactory?

有没有更好的方法来实现这一点,也许不必创建一个DocumentBuilderFactory

采纳答案by Daniel Fortunov

It is quite difficult to predict what concrete JAXP factory implementation will be loaded without actually creating an instance because the process for selecting an implementation.

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

From the Official JAXP FAQ(Question 14):

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

When an application wants to create a new JAXP DocumentBuilderFactoryinstance, it calls the staic method DocumentBuilderFactory.newInstance(). This causes a search for the name of a concrete subclass of DocumentBuilderFactoryusing the following order:

  1. The value of a system property like javax.xml.parsers.DocumentBuilderFactoryif it exists and is accessible.
  2. The contents of the file $JAVA_HOME/jre/lib/jaxp.propertiesif it exists.
  3. The Jar Service Provider discovery mechanism specified in the Jar File Specification. A jar file can have a resource (i.e. an embedded file) such as META-INF/services/javax.xml.parsers.DocumentBuilderFactorycontaining the name of the concrete class to instantiate.
  4. The fallback platform default implementation.

当应用程序想要创建新的 JAXPDocumentBuilderFactory实例时,它会调用 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. 回退平台默认实现。

Adding to this complexity, each individual JAXP factory can have an independent implementation specified. It is common to use one parser implementation and another XSLT implementation, but the granularity of the selection mechanism above allows you to mix and match to an even greater degree.

更复杂的是,每个单独的 JAXP 工厂都可以指定一个独立的实现。通常使用一个解析器实现和另一个 XSLT 实现,但上述选择机制的粒度允许您在更大程度上混合和匹配。

The following code will output information about the four main JAXP factories:

以下代码将输出有关四个主要 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());
}

The following sample outputillustrates a mix-and-match of three different JAXP implementations (Built-in Xerces and external JARs for Xerces 2.8 and Xalan) working together:

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

回答by jarnbjo

It depends, but generally no.

这取决于,但通常不会。

DocumentBuilderFactory.newInstance()will either return the implementation of DocumentBuilderFactorywhich is configured in the system property "javax.xml.parsers.DocumentBuilderFactory" or the JRE's default factory if the system property is not set. The default factory is most likely hard coded in the implementation of the newInstance method and not otherwise accessible.

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

If the system property is set, you could at least use the getResource method on the relevant class loader to get the URL, from which the class loader would load the corresponding class file. If it is from a jar file, you should be able to extract the file name (or source URL) from the jar: URL. Detailed package information should also be available if you manaully read the meta data files from the classpath.

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

If the system property is not set, I'm pretty sure that you have no way to get the information you are looking for without actually creating a new factory as you're already doing.

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

回答by jwd630

There is another location that is searched before the "fallback platform default implementation" and that is the java.endorsed.dirsdirectory as documented in the Java Endorsed Standards Override Mechanism

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

The Endorsed Standards Override Mechanism provides a means whereby later versions of classes and interfaces that implement Endorsed Standards or Standalone Technologies may be incorporated into the Java Platform.

Endorsed Standards Override Mechanism 提供了一种方法,可以将实现 Endorsed 标准或独立技术的类和接口的更高版本合并到 Java 平台中。

回答by zg_spring

it is easy, you just set

很简单,你只需设置

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

the track will tell you whick impl,and whick way jaxp use.

该曲目将告诉您 impl 和 jaxp 的使用方法。

回答by trang

Just add

只需添加

-Djaxp.debug=1

to JAVA_OPTSand you will see such information.

JAVA_OPTS,您将看到此类信息。

For more detail: https://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilderFactory.html

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