在不实际创建实例的情况下,很难预测将加载哪些具体的 JAXP 工厂实现,因为选择实现的过程。
来自 JAXP 官方常见问题解答(问题 14):
当应用程序想要创建新的 JAXP 实例时,它会调用 staic 方法 。这将导致使用以下顺序搜索具体子类的名称:DocumentBuilderFactory
DocumentBuilderFactory.newInstance()
DocumentBuilderFactory
- 系统属性的值,例如它是否存在且可访问。
javax.xml.parsers.DocumentBuilderFactory
- 文件的内容(如果存在)。
$JAVA_HOME/jre/lib/jaxp.properties
- Jar 文件规范中指定的 Jar Service Provider 发现机制。jar 文件可以有一个资源(即嵌入文件),例如包含要实例化的具体类的名称。
META-INF/services/javax.xml.parsers.DocumentBuilderFactory
- 回退平台默认实现。
除了这种复杂性之外,每个单独的 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