前言
在web开发中经常碰到classpath与classpath* 的概念,具体的含义从网络中能了解个大概,这篇文章将从代码中来认识它们
正文
java web开发,在web.xml中经常使用到classpath与classpath*,如下例子
spring的配置文件在web.xml的配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/spring-*.xml,classpath*:config/dispatcher-servlet.xml</param-value>
</context-param>
log4j的配置文件在web.xml的配置
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:config/log4j.properties</param-value>
</context-param>
网上说这两者的区别是classpath只加载当前项目的classpath路径下的资源,而classpath*在加载当前项目的classpath路径下的资源同时也会加载到jar的资源。这个结论是从哪里得出来的,是官方的文档还是从源码中得知的? 是否真的如上面说的那样呢?
从上面的两个配置可以看到,classpath与classpath*是配置在xml中的,也就是说当spring框架或者log4j框架在web.xml的监听器加载初始化的时候需要读取这两个路径。我从两者框架源码中发现无论是classpath还是classpath* 只不过是一个标识而已(ignore:如同将复杂的业务,抽象成面向对象,需要很多很多的变量来表现),两者框架都会做一步以下的操作
String resourcePath = "classpath:/config/log4j.properties" ;
if(resourcePath.startsWith("classpath")) {
//使用classloader加载,在web中就是tomcat提供的WebappClassLoader加载器
//它默认就会去WEB-INF/classes 和WEB-INF/lib这两个目录下加载
//所以可以加载到WEB-INF/classes下的资源,也可以加载到WEB-INF/lib中jar的资源
//使用加载器加载可以得到URL,然后使用URL.openConnection打开流操作
}else {
//如果不是classpath开头,那么认为资源在本地工程
//如果是log4j的话,使用servletContext.getRealPath();
//得到在当前项目的资源路径并用new URL(path)包装,最后采用URL.openConnection打开流操作
//如果是spring,无论是classpath还是/WEB-INF/..这样的配置都会用上面的WebappClassLoader加载,加载器得到的URL openConnection来打开流操作
}
从上面的代码以及注释可以知道,加载资源可以用加载器(不同加载器有不同的加载目录,这里是tomcat提供的webappclassloader)加载默认目录的资源,也可以是指明一条本地文件系统的路径,然后用new URL(localFileSystemPath) 来加载资源(如何获取资源所在的本地文件系统的完整路径,这里方法很多,后面文章再做总结)
从上面的分析可以看出classpath与classpath* 还真不能用资源是否在jar包下来区分,不同的框架有着不同的处理,可能一些框架还不认你classpath或者classpath*呢。比如下面代码在classpath后面加了一个*号导致异常,因为log4j在解析的逻辑代码中不支持classpath*
仅仅是str.startWith("classpath")
来区分实现不同逻辑而已
错误的log4j资源路径配置
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath*:config/log4j.properties</param-value>
</context-param>
加载jar包资源
加载jar的资源其实没那么神秘,使用webappclassloader就可以加载到WEB-INF/lib下的jar资源了,再用jar包的api操作
private void deal() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();//使用tomcat启动时存放到线程中的加载器
if(loader == null) {
loader = Log4jController.class.getClassLoader(); //使用加载当前类的加载器
}
try {
Enumeration<URL> urls = loader.getResources("/config");
while(urls.hasMoreElements()) {
URL url = urls.nextElement();
System.out.println(url);
}
} catch (IOException e) {
e.printStackTrace();
}
}
下载的jar操作待补充