发现问题:
SAXParserFactoryImpl 出现ClassNotFoundException 与
运行环境:jdk,jre,运行环境还跟jdk版本有关。现在流行的是jdk8,jdk7快要淘汰了, jdk6已经不用了。
当时还猜测与Tomcat版本有关,tomcat6、tomcat7,当时发生问题的是Web容器是 tomcat7,还猜测过于IDE的版本有关。
提取关键字:
JAXP
Crimson 解析器
Xerces
运行可执行的 jar包
CLASSPATH
jaxp.properties
平台无关性
JAXP 实际使用的是 Crimson 解析器,发现还会解析 XML文件时出现错误,
经过分析, Crimson 解析器 是Sun公司开发的(实际使用发现 Crimson 没有 Xerces 解析器 稳定),
打包在 JAVA_HOME/lib/dt.jar包中,这个dt.jar被设置在环境变量 CLASSPATH 中了,
当运行可执行的 jar包 时,JAXP 会使用 CLASSPATH 的解析器,
在Web工程中的War包则不会。
通过阅读JDK源码
javax.xml.parsers.FactoryFinder,
javax.xml.parsers.SAXParserFactory
DocumentBuilderFactory
发现 JDK 按照如下顺序(查找可使用的解析器):
1.系统属性 javax.xml.parsers.DocumentBuilderFactory 或 javax.xml.parsers.SAXParserFactory
2.在 jdk-dir/lib/jaxp.properties 中设定的 javax.xml.parsers.DocumentBuilderFactory 或 javax.xml.parsers.SAXParserFactory 属性
3.运行时jar包中META-INF/services/javax.xml.parsers.DocumentBuilderFactory或javax.xml.parsers.SAXParserFactory文件中设定的值
4.如果上面的解析器都没有找到,则使用Crimson。
如果还没有,就会报 ClassNotFoundException 异常了。
通过JAXP查找解析器的顺序
(按照上面从小到大的数字顺序:系统属性>jaxp.properties>META-INF>Crimson),
我们可以使用下面方式来决定,我们使用的实际解析器,
1.在程序中写死实际的解析器
如
javax.xml.parsers.DocumentBuilderFactory factory= new org.apache.crimson.jaxp.DocumentBuilderFactoryImpl();
2.使用JAXP的 DocumentBuilderFactory 工厂类,
如
javax.xml.parsers.DocumentBuilderFactory factory= javax.xml.parsers.DocumentBuilderFactory.newInstance();再通过下面的方式来指定实际的解析器类
方法一: 在运行java时,通过设置(java程序的命令) java -D javax.xml.parsers.DocumentBuilderFactory=new org.apache.crimson.jaxp.DocumentBuilderFactoryImpl
方法二: 在程序中调用 System.setProperty("javax.xml.parsers.DocumentBuilderFactory","org.apache.crimson.jaxp.DocumentBuilderFactoryImpl") 来设定实际的XML解析器.
方法三: 编写一个 jaxp.properties 文件,在其中加入如下内容
javax.xml.parsers.DocumentBuilderFactory=org.apache.crimson.jaxp.DocumentBuilderFactoryImpl
再将此文件放入 JAVA_HOME/lib/ (目录)下
方法四: 在打jar包下,在目录 META-INF/ 下新建一个 services 目录,
在此目录新建一个文件名为 javax.xml.parsers.DocumentBuilderFactory 的文件,
文件内容写上实际使用的解析器类,如写org.apache.crimson.jaxp.DocumentBuilderFactoryImpl
(总结:)
通过上面发现过程,就可以对 JAXP 有一个比较深的了解。
其实, JAVA 中有许多实际操作中会应用到这种思想,就是平台无关性,
发展到不依赖于具体的实现。
如我们熟悉的JNDI,JDBC,JAXP等。
JNDI是抽像各种目录服务操作的类库,
目录服务器厂商太多了,如SUN公司的ldapsdk,还有novell公司等等;
JDBC是抽像各种数据库操作的类库,
数据库厂商也太多了,如ORACLE,SQLSERVER,MYSQL,INFORMIX等等;
JAXP就是抽像各种XML解析器和转换器产品的类库,
XML解析器和转换器产品够多的了。
JAXP解析器:
Crimson 解析器
Xerces 解析器
CLASSPATH 的解析器(这个应该是泛指加入到此目录下的jar文件)