Spring提供了一个工具类可以加载classpath下的文件,一般情况下无任何问题,但是当它作为公共的jar包中的工具来加载jar包中的文件时则报出找不到文件的错误.

点开看了一下这个工具类ResouceUtils.getFile()方法的源码:

public static File getFile(String resourceLocation) throws FileNotFoundException {
Assert.notNull(resourceLocation, "Resource location must not be null");
if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
String description = "class path resource [" + path + "]";
ClassLoader cl = ClassUtils.getDefaultClassLoader();
URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
if (url == null) {
throw new FileNotFoundException(description +
" cannot be resolved to absolute file path because it does not exist");
}
return getFile(url, description);
}
try {
// try URL
return getFile(new URL(resourceLocation));
}
catch (MalformedURLException ex) {
// no URL -> treat as file path
return new File(resourceLocation);
}
}

看了一下代码结构简单逻辑清晰,可能有问题的也就是上图标红的2处.这里我第一印象是类加载器加载资源的时候没加载到.Debug了一下cl.getResource(path)用的类加载器是

WebAppClassLoader,想看一下内部实现,但是到这里就跟不进去了,然后百度了一下发现这个是Jetty实现的自己的ClassLoader,截取部分关键的加载源码:

public void addJars(Resource lib)  {
if (lib.exists() && lib.isDirectory())
{
String[] files=lib.list();
for (int f=0;files!=null && f<files.length;f++) {
try {
Resource fn=lib.addPath(files[f]);
String fnlc=fn.getName().toLowerCase();
if (fnlc.endsWith(".jar") || fnlc.endsWith(".zip")) {
String jar=fn.toString();
jar=StringUtil.replace(jar, ",", "%2C");
jar=StringUtil.replace(jar, ";", "%3B");
addClassPath(jar);
}
} catch (Exception ex) {
Log.warn(Log.EXCEPTION,ex);
}
}
}
}

上面这块是把jar和zip的path加到类加载器路径中的部分源码.继续debug得到

URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));

上面的url结果:

实际上取到了要加载的文件路径,由于在jar包中,协议字段被标识为jar.到这里看来并非类加载器导致的加载文件失败.那只好继续debug往下看getFile()的源码:

public static File getFile(URL resourceUrl, String description) throws FileNotFoundException {
Assert.notNull(resourceUrl, "Resource URL must not be null");
if (!URL_PROTOCOL_FILE.equals(resourceUrl.getProtocol())) { //URL_PROTOCOL_FILE="file"
throw new FileNotFoundException(
description + " cannot be resolved to absolute file path " +
"because it does not reside in the file system: " + resourceUrl);
}
try {
return new File(toURI(resourceUrl).getSchemeSpecificPart());
}
catch (URISyntaxException ex) {
// Fallback for URLs that are not valid URIs (should hardly ever happen).
return new File(resourceUrl.getFile());
}
}

看到这里有点无语了,上面红色字体的部分实际判断资源路径的协议是否为file,由于在jar包中,协议是jar,故到此处直接抛出文件未找到的异常,

顿时觉得自己好傻,debug这么久,又理了一遍类加载的过程,其实问题是很简单的一个问题,ResouceUtils.getFile()是专门用来加载非压缩和Jar包文件类型的资源,所以它根本不会

去尝试加载Jar中的文件,要想加载Jar中的文件,只要用可以读取jar中文件的方式加载即可,比如 xx.class.getClassLoader().getResouceAsStream()这种以流的形式读取文件的方式.

ResouceUtils.getFile()取不到Jar中资源文件源码小结的更多相关文章

  1. eclipse中导入jar文件的源码

    有时候想看看一个jar包的源码是怎么写的,想按Ctrl+鼠标左键点击来自动导航这时候就需要先把源码给导入到eclipse中,步骤如下:首先准备jar包和源文件包比如:

  2. 各个版本spring的jar包以及源码下载地址

    各个版本spring的jar包以及源码下载地址,目前最高版本到spring4.1.2,留存备用: http://maven.springframework.org/release/org/spring ...

  3. Eclipse开发环境debug模式调试断点从jar跳到源码

    Eclipse开发环境debug模式调试断点从jar跳到源码 说明:本案例使用jsch-0.1.54.jar和源码做test,项目分成两个,一个是jsch的源码,另一个是测试案例 一.下载JSch.的 ...

  4. Eclipse里面的Maven项目如果下载依赖的jar包的源码

    Window---------Properties---------------Maven--------------勾选Download Artifact Sources和Download Arti ...

  5. Eclipse中调试Jar包的源码(调试Struts2源码)

    首先在Eclipse中创建一个新的项目,加入运行Struts2所需要的JAR文件,并将它们加到项目的CLASSPATH中(在Lisbs中右击 build path 如下图: ),成功后的界面如图 1- ...

  6. eclipse调试第三方jar包需要源码的问题

    很多时候测试自己的jar包功能时,需要有一个测试工程导入该jar包,但是一般在调试的时候,需要跟进去看看步骤和逻辑是否正确,这个时候就需要在jar包的源码中下断点.最近刚好自己也会经常这样做,也遇到了 ...

  7. MyEclipse中android 项目如何解决第三方jar无法关联源码的问题( The JAR of this class file belongs to container 'Android Private Libraries' which does not allow modifications to source attachments on its entries.)

    若我们要为第三方jar(android-support-v4.jar)关联源码通常的做法是 右键项目 单击菜单Properties 单击菜单 Java Build Path 单击 Libraries ...

  8. IDEA 全局搜索 Jar 包中源码内容

    引言 项目开发过程中,经常遇到需要在依赖的 Jar 包查看源码,查找类方法和属性,介绍两种在 IDEA 中搜索 Jar 包内容的方式 方式一:双击 SHIFT 快捷键 输入需要查询的类名或方法名 方式 ...

  9. htmlunit抓取js执行后的网页源码

    上次我不是写了一个自动抓取博客访问量吗 (点击打开链接) 可是昨天晚上我又运行的时候,发现不能用了.. 运行了几次 发现使用URLConnection 得到的网页源码和浏览器直接查看的不同. URLC ...

随机推荐

  1. 关于JAVA中包装类的是什么类型传递这个问题的笔记

    背景知识: 如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值.如果在函数中改变了副本的值不会改变原始的值. 如果参数类型是引用类型,那么传过来的就是这个参数的引用,这 ...

  2. leetcode 29-> Divide Two Integers without using multiplication, division and mod operator

    class Solution(object): def divide(self, dividend, divisor): """ :type dividend: int ...

  3. SqlParameter的两种用法【二】

    private void Loadprovince() { string sql = "select * from Tables where ArealdPid=@pid"; /第 ...

  4. 《剑指offer》第五十六题(数组中只出现一次的两个数字)

    // 面试题56(一):数组中只出现一次的两个数字 // 题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序 // 找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度 ...

  5. Linux学习3-yum安装java和Tomcat环境

    前言 linux上安装软件,可以用yum非常方便,不需要下载解压,一个指令就能用yum安装java和tomcat环境. 前面一篇已经实现在阿里云服务器上搭建一个禅道系统的网站,算是小有成就,但并不是每 ...

  6. 优雅地记录Python程序日志1:logging模块简介

    本文摘自:https://zhuanlan.zhihu.com/p/31893724 本篇涉及: logging模块的调用: 保存log日志为文件: 调整输入日志等级: 修改日志消息格式: 前言 在使 ...

  7. HTML如何实现滚动文字

    HTML如何实现滚动文字 一.总结 一句话总结:marquee标签,也可以用js和css来实现 marquee标签 也可jss和css <marquee><span style=&q ...

  8. C# 遍历文件夹筛选目标文件

    有近400G的数据,首先需要写程序把目标文件标准化名称(相当耗时,各种情形,间接说明在数据采集过程中标准化操作的重要性,这样会给后续处理带来很多不必要的麻烦和消耗) 网上找了个方法还不错,还有一种递归 ...

  9. 非常棒的——python Deep learning 学习笔记

    https://www.cnblogs.com/zhhfan/p/9985991.html

  10. Composer 的学习

    一.Composer简介 Composer 是PHP用来管理依赖关系的工具. 使用 composer 的必要前提有: 1.PHP版本要高于PHP5.3.2 2.PHP支持OpenSSL扩展 3.安装有 ...