关键方法就是getResource方法,ClassPathXmlApplicationContext的资源定位就是采用了DefaultResourceLoader的getResource方法。内部也没有做太多的工作,其实就是如下的代码:
try
{
// Try to parse the location as a URL...
URL url = new URL(location);
returnnew UrlResource(url);
}
catch (MalformedURLException ex)
{
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
上面的代码都是标准的j2se的代码.作为URL通过字符串来构造,通常需要能够首先获得URL的资源全路径,而在当前情况下发现到获取资源的时候location还是保持了spring/的状态,而没有被替换成为所在jar的资源全路径,那么就先作以下测试:
新建简单的项目,然后在项目中加入包含spring配置的jar,然后作单元测试,测试代码如下:
URL url = Thread.currentThread().getClass().getResource("/spring/");
未获取到URL,出现异常。
URL url = Thread.currentThread().getClass().getResource("/spring/sip-analyzer-dataSource.xml");
正常获取到了URL。
由此看来应该是在获取Jar中的目录资源路径的时候出现问题导致后续载入出现问题,尝试直接传入具体的文件名:
ctx = new ClassPathXmlApplicationContext("/spring/sip-analyzer-dataSource.xml");
发现还是出现问题,在new URL的时候传入的是没有翻译过的文件名,考虑在传入的过程中就直接替换成为资源路径,因此写了一个简单的方法:
publicstatic String[] getRealClassPath(String[] locationfile)
{
String[] result = locationfile;
for(int i = 0 ; i < locationfile.length; i++)
{
try
{
URL url = Thread.currentThread().getClass().getResource(locationfile[i]);
String file = url.getFile();
if (file.indexOf(".jar!") > 0)
result[i] = newStringBuffer("jar:").append(file.substring(0,file.indexOf(".jar!")+".jar!".length()))
.append(locationfile[i]).toString();
}
catch(Exception ex)
{}
}
returnresult;
}
在将构造工厂类修改为:
ctx = new ClassPathXmlApplicationContext(BaseUtil.getRealClassPath(new String[]{"/spring/sip-analyzer-dataSource.xml"}));
运行测试,正常启动,这也就是又变成最原始的文件罗列的模式。问题虽然找到了解决方案,但是始终觉得很别扭,同时对于无法在Jar中载入配置资源的情况我一直都还是觉得应该不是Spring的问题。
峰回路转:
晚上到家还是有点不死心,就直接建了个项目作单元测试,然后将一个自己建立的Jar加入到Classpath下面,作单元测试,结果大吃一惊。
URL url = Thread.currentThread().getClass().getResource("/test/");
URL url = Thread.currentThread().getClass().getResource("/test/test.txt");
都正常获取到了资源,这完全推翻了我早先认为在Jar中无法获得目录作为资源的问题。然后把公司里面的项目重新打包然后加入到ClassPath下,验证spring的目录,出错,目录无法获取,此时我确定看来应该不是应用的问题,而是环境问题。检查了两个Jar,看似没有什么区别,将公司项目的Jar中的spring目录拷贝到测试的jar中,然后作测试,可以找到目录。那么问题完全定位到了Jar本身。通过RAR的压缩工具看了一下两个Jar的信息,除了显示所谓的压缩平台不同(一个是DOS,一个是Unix)其他没有任何区别。然后自己用RAR打了一个Jar以及在linux下打了一个Jar做了测试,两个Jar内的目录都是正常可以被获取。
无意中我换了一下需要获取的目录名称,也就是说在公司项目中有多个目录在jar中,这次换成为ibatis目录,正常获取,看来不是Jar的格式。回想了一下,公司的打包工具是自己人写的,其中提供了一个特性,如果一个项目内部的一些配置信息是需要让调用它的第三方在编译期配置,那么可以通过在第三方项目构建的过程中,动态的生成配置文件然后植入到被依赖的jar中。而spring这个目录中由于那些数据库的配置都是需要动态配置的,因此spring的那个目录是后期被写入的,而ibatis是早先就固化在项目中的。
由于我们的Jar在META-INF中都有INDEX.LIST文件,过去遇到过在JAR中自己手工放入一些文件由于没有修改INDEX.LIST而导致虽然文件已经存在但是不会被发现,于是打开公司项目中的Jar,果然INDEX.LIST中只有ibatis,而没有spring,看来是我的同事在写入的时候没有将INDEX.LIST更新。立刻将INDEX.LIST作了更新,测试spring目录,结果依然出错。看来这还不是问题的根本。
立刻问了我们开发打包工具的同事,向他们要写入Jar的代码,对方的回答是就是采用简单的JarOutputStream来写入,没有什么特殊的。那我就开始怀疑是否是因为采用这种方式写入到Jar中的目录在被资源定位的时候会出现问题。于是写了下面的代码:
JarOutputStream jos;
try
{
jos = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
String f = "spring/sip-analyzer-dataSource.xml";
File source = new File(f);
JarEntry je = new JarEntry(f);
jos.putNextEntry(je);
BufferedInputStream bis = new BufferedInputStream(newFileInputStream("D:/work/sip3/analyzer/src/conf.test/spring/sip-analyzer-dataSource.xml"));
int i = 0;
while ((i=bis.read())!=-1)
{
jos.write(i);
}
bis.close();
jos.closeEntry();
jos.close();
} catch ...
结果创建出来的Jar中的spring目录无法被资源定位,同样在这个Jar中直接拖入一个目录test,然后刷新测试,test目录可以被定位。
后续
就到了这个阶段来看如果以上面这种方式写入,对于目录资源定位的却存在问题。这个问题还没有最终的肯定的结论,在我现在所有的试验来看,不论是否有INDEX.LIST,或者INDEX.LIST,如果用程序写入到Jar中,目录作为资源定位都会出现问题(起码是上面那种普通写入方式)。
这种情况可能是由于这种写法还有一些其他需要配置的,例如写入到META-INF/INDEX.LIST中,或者就是J2SE现在API存在的一个问题。不过不管是什么问题,起码值得引起重视,特别是现在类似于Spring框架载入Jar目录下的配置。
相关推荐
开发完毕,部署的时候,将开发的class打成一个可执行jar包,会发现通过Class.forName(String classname) 或ClassLoader.getSystemClassLoader().loadClass(String classname)来动态载入存在于第三方jar包中的class会抛...
该资源是AES加密工具类; 包括源码:AES256Util.java 及其必要jar包:bcprov-jdk16-141.jar 和 javabase64-1.3.1.jar
java 载入dll之后无法切换输入法测试工程(My Eclipse)
在公司开发java项目整合润乾报表,原来的jar包有问题,替换上这个包问题立刻就解决打印、导出等问题了。
(11) spring-web.jar 这个jar文件包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、 Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类。 (12) ...
3、点击菜单【文件】-【载入 jar...】找到我们的手机JAVA程序(可从网上下载),一般为jar格式,然后耐心等一会就可以看到KEmulator Lite运行手机程序了。 4、点击菜单【视图】-【模拟键盘】可打开模拟键盘,左软...
Java动态生成代码并编译载入 Java动态生成代码并编译载入
rhino-1.7.14.jar下载
aspectjweaver.jar是java Spring aop 编程必导入的jar包之一
不同于Java传统的使用单个类加载器载入classpath中的所有JAR文件,每一个库(library,可以理解为完成某一个功能的一系列jar的组合)成为一个module,该module仅链接其依赖的其他module,而不再依赖其它任何资源。...
worldwind java 3d模型载入源代码
在Java_3D中载入外部3D模型文件.pdf
本人的运行环境是Eclipse EE+tomc7.0+jre1.7+载入的jar包有:msbase.jar、msutil.jar、mysqlserver.jar。mysql数据库密码为123456 代码粗糙,只适合初学者。再次声明! 如下载者有不可解决问题的请联系我QQ邮箱:...
本书特色有:说明JDK,JRE与JVM三者的关系:探讨Java应用程序的执行流程,让您以后不会再为JDK与JRE的版本问题苦恼;讲解类别载入器的运作机制:类别载入器兼具Java程序的弹性与安全性两项重大任务,您不能不了解它...
(附件中提供了该工具包的jar包,及源文件以供研究) BeanUtils Commons-BeanUtils 提供对 Java 反射和自省API的包装 Betwixt Betwixt提供将 JavaBean 映射至 XML 文档,以及相反映射的服务. Chain Chain 提供...
JVM(java virtual machine java虚拟机):java程序会载入JVM,然后运行。 java核心类库:java程序在运行的过程中需要依赖一些库文件。 JDK(java development kit) java开发工具。 JDK包含JRE,我们直接安装...
该报用于美化java界面,载入包后加入如下代码: try { UIManager.setLookAndFeel("org.jvnet.substance.skin.SubstanceFieldOfWheatLookAndFeel"); } catch (ClassNotFoundException e) { // TODO 自动生成的 ...
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。...这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。
资源介绍:。易语言Javalib_static.lib支持库中文名为易语言Java支持库,本易语言支持库使易语言具备了访问Java类库的能力。“Java虚拟机”和“Java本地接口”是本支持库中最重要的两个数据类型。由“Java虚拟机”...
有时候需要在运行时根据模板和数据动态生成 Java 代码,然后对其进行编译生成 Class 文件,然后再将这些类加载 进去,并使用反射来创建对象。