明明jar包已经引入了,并且编译不报错,但是运行却还提示classnotfound,什么原因?
我在写cxf的客户端代码调用cxf接口的时候,编译不报错,但是运行这一句的时候的时候报错:
Client client = clientFactory.createClient("http://XX.XX.XX.XX:8080/XX/XXService?wsdl");
报错提示:
Caused by: java.lang.ClassNotFoundException: com.sun.tools.internal.xjc.api.XJC//缺少的class,即jar包
···
···
at org.apache.cxf.common.jaxb.JAXBUtils.createSchemaCompiler(JAXBUtils.java:672)//出错的class,即运行出错的class
我发现该class在tool.jar中,所以将tool.jar引入。运行还是报错:
Caused by: java.lang.ClassNotFoundException: com.sun.tools.internal.xjc.api.XJC,明明我已经引入了,这就奇怪了。
我现在有两个疑问:
1)既然缺class(即却jar包),为什么编译不报错?
这个很好理解,因为我的java代码中这一句是没有编译错误的:
Client client = clientFactory.createClient("http://XX.XX.XX.XX:8080/XX/XXService?wsdl");
这就是封装的弊端了,封装(即引入class文件,即jar包)是java的特点和优势,同时也是它的劣势。因为劣势就表现在编译的时候,不能深入class文件去编译,就算被封装的class(即jar包中的某个class)的代码中缺少另一个class即jar包,编译的时候也不会报错。只有运行的时候才会报错。
2)既然包含这个class的jar包已经引入了,为什么运行还报错?
这就是classloader的问题了,即class文件的加载原理(即java代码中import的class,是从哪个路径下获取下获取并加入到内存中的)。
所以,包含com.sun.tools.internal.xjc.api.XJC的jar包已经引入了,还报错的原因,就出在classloader。
原因是:
我引入的jar包如A.jar中某个class如a.class中(其实是a.class的源代码即a.java中)import了com.sun.tools.internal.xjc.api.XJC,而A.jar中的MANIFEST.MF文件,设置了jar包依赖的jar包的路径,如B.jar、C.jar两个。因此在a.class运行的时候,classloader会去A.jar包的MANIFEST.MF文件制定的依赖jar包中找com.sun.tools.internal.xjc.api.XJC这个class,而B.jar、C.jar根本没有引入,或者B.jar、C.jar中没有com.sun.tools.internal.xjc.api.XJC这个class,就会报错了。
classloader这个东西,这么傻、这么不智能吗?如果去A.jar的依赖的jar包即B.jar、C.jar中找不到com.sun.tools.internal.xjc.api.XJC这个class,就不会去整个lib库中去搜索吗?
这就要看classloader的原理了,看是不是这么回事。
======classloader的原理,加载依赖jar包:
还有一个原因我忽略了:
classA中的代码提示classB不存在,即classnotfound,并不是classB没有在classA中import,而是根本不需要import,因为classA和classB在一个目录下边,不需要import。
所以是因为classA路径下,没有classB这个类,所以报错,classnotfound。而根本不需要import。
----看来要找到原因,只能在调试的时候,引入源码了。
例子,以及调试过程见:
http://blog.****.net/ideality_hunter/article/details/73613161,链接中的文章,通过深入调试源码,彻底明白了了classnotfound的原因,以及找到了解决办法,此问题完美解决。