发现问题:
前段时间使用ClassLoader类的方法来加载classPath路径下的配置文件,其中用到getSystemResource(String name)
、getSystemResourceAsStream(String name)
、getSystemResources(String name)
这几个方法的时候出现问题。
问题出现在,程序用main方法的方式运行的时候能够正常运行,但是使用tomcat运行的时候就会报空指针异常。
原因:
两种方式运行的ClassLoader加载机制不同,导致了不同的结果。
main方法运行是启动的本地的jdk来加载类,加载机制是:
Java默认提供的三个ClassLoader
-
BootStrap ClassLoader:称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等,这个是通过native方法调用C语言实现的。
-
Extension ClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
-
App ClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。
-
所以classPath路径下的资源都是由AppClassLoader来加载的。
Tomcat的ClassLoader加载机制
tomcat实现了自己的一套类加载器,它的Extension ClassLoader与jvm是相同的,但是没有使用App ClassLoader来加载自己项目里的类和资源。
整个Tomcat的classLoader分为了两条线,左边的一条线为catalinaLoader,这个是Tomcat服务器专用的,用于加载Tomcat服务器本身的class,右边的一条线则为web应用程序用的,每一个web应用程序都有自己专用的WebappClassLoader,用于加载属于自己应用程序的资源,例如/web-inf/lib下面的jar包,classes里面的class文件。。。
然后上面也体现了整体的classLoader的双亲继承关系。。。。
详细可以看这里http://blog.csdn.net/fjslovejhl/article/details/21328347
这三个方法
getSystemResource(String name)
、getSystemResourceAsStream(String name)
、getSystemResources(String name)
内部实现的时候都是用到了ClassLoader system = getSystemClassLoader();的方法,获取的ClassLoader都是App ClassLoader所以在使用tomcat运行的时候就会取不到classPath路径下的资源,因为都是WebappClassLoader加载的。
解决办法:
使用 当前类.class.getClassLoader().getResource(String name)
、getResourceAsStream(String name)
、getResources(String name)这三种方法。