在没有实际创建实例的情况下,很难预测将加载哪些具体的 JAXP 工厂实现,因为选择实现的过程。
来自官方 JAXP 常见问题解答(问题 14):
当应用程序想要创建一个新的 JAXPDocumentBuilderFactory
实例时,它会调用 staic 方法
DocumentBuilderFactory.newInstance()
。这将导致
DocumentBuilderFactory
使用以下顺序搜索具体子类的名称:
- 系统属性的值,例如
javax.xml.parsers.DocumentBuilderFactory
它是否存在且可访问。
- 文件的内容(
$JAVA_HOME/jre/lib/jaxp.properties
如果存在)。
- Jar 文件规范中指定的 Jar 服务提供者发现机制。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