有时候想测试一段代码,但是代码中引入了外部包,因为不想每次测试一小段代码就使用myeclipse或者别的ide,最好使用editplus就可以做完测试,而在导入外部包的时候有两种做法
1)在dos中使用set classpath
2)将外部包放到jre安装目录下的ext文件夹中
第一种方法的缺点很明显:当需要导入的外部包过多时,classpath的值过长,设置起来麻烦,容易出错
第二种几乎没什么缺点,但是总感觉把外部包添加到ext文件夹中,累积下来,会对以后的测试其他的代码有影响,这纯属个人原因,所以不想使用这个方式。
那有没有简单的方法呢?
我想到的是使用代码来完成第一种方法
也就是编写一个类方法,通过调用
Runtime.getRuntime().exec(“cmd set classpath=“+“classpath路径”);来设置classpath的路径
public static String getClassPath(String path){
StringBuffer temp=new StringBuffer();
File jarDir=new File(path);
File[] jarFiles=jarDir.listFiles();
for(File file:jarFiles){
if(file.isFile()&&file.getName().endsWith(".jar")){
temp.append(file.getAbsolutePath()+";");
jarNum++;
}
else if(file.isDirectory()){
temp.append(getClassPath(file.getAbsolutePath()));
}
}
return (temp.toString());
}
通过上面的方法获取某个文件夹中所有的所需jar包的绝对路径,并将其返回值传给Runtime.getRuntime().exec(“cmd set classpath=“+“classpath路径”);来设置classpath;
或者是通过System.setProperty(“java.library.path”,“classpath路径”)来修改classpath的值,但是事实上,通过System.getProperty(“java.library.path”)发现确实修改成功了,但jar包导入失败。程序包classnotfound异常
百度白天无果,google后终于发现了些问题
Java程序启动后再动态修改classpath并没有我想象中的那么简单,但是英文比较烂,看的不是很懂,有兴趣的可以自行google关键词:“setting the classpath at runtime” 在此我贴出一些解释
1)The classloader represents (part of) a namespace, and two otherwise identical classes loaded by different classloaders are not “equal”. Which means there are a few dangers lurking in classloading, notably singletons suddenly not being so single anymore as well as casts failing unexpectedly.
2)Classloaders (should) work on a pattern of delegating to the “parent” loader before attempting anything themselves (see above).
3)Class loading and linking are two distinct steps (even though example implementations of a classloader such as may be found in blog posts/online Java articles, will combine the two into one for simplicity) Therefore you should not assume that if a parent loader has loaded a class it has also loaded all dependencies …
4)All this means there is a problem if class A loaded by loader A references a class B which neither loader A nor any of its parents can load: class A may load just fine in loader A but at the point of use it fails because loader A cannot fully resolve (link) it.
5)And you should make sure that your classloader loads classes in a synchronized manner otherwise the issues hinted at in step #1 can leap from duplicates due to classloaders to duplicates from multiple threads using the same classloader as well…
//简单的翻译以下:(翻译不出来的就略过)
1)类加载器代表的是一个命名空间,两个完全相同的类(同一个.class文件)被不同的加载器加载时并不相等,这也就意味着,在加载时会潜伏这一些危险,尤其是单例类突然变得不是单例……
2)类加载器在做自己的事之前应该建立(工作)在一个授权给父加载器的模式中(瞎翻译的。。。)
3)类的加载和连接是两个不同的步骤(。。。。。),因此你就不要妄自猜测如果一个父加载器加载了一个类,它就会加载这个类的所有依赖类
4)这也就意味着如果一个类A被A的加载器所加载,那么依赖类B既不会被A的加载器加载也不会被他的父加载器加载,类A可能会被加载成功,但使用类A失败的愿意在于A的加载器不能连接所有的依赖类,这就是问题所在。
5)如果你想确保你的加载器加载类时在一个同步管。。。。。(后面的不懂)
以我自己的理解就是,我虽然修改了classpath的值,但是类加载器已经启动了,在我启动程序的时候就启动了,而我再修改其classpath的值已经对那个已经启动的类加载器或者说是jvm不起作用了。
这个很好验证,在调用某个依赖与某个外部包的类之前使用Thread.sleep(10*1000)让其休眠10s钟,启动jvm之前不要将外部包导入到程序中,然后运行代码,程序在进入休眠中时将外部包复制到ext文件夹中,明显,会classnotfound。
这只是我个人的理解,其他的还不明白,待究。