我们的Java应用程序依赖于网络共享上可用的一些资源。此网络共享位于类路径上,并且使用MyClass.class.getResourceAsStream("/myfile.jpg")
在运行时读取资源。
java -Djava.class.path=\\myserver\myshare:C:\myjar.jar MainClass
当分享在启动时可用时,一切都顺利进行。可以使用getResourceAsStream()
读取位于共享中的图像和属性文件。但是,如果应用程序启动时共享不在线,即使在读取任何资源之前共享联机,也无法使用getResourceAsStream()
读取它们。
使用eclispse +反编译器进行一些挖掘,我注意到了一个区别。默认的类加载器继承自URLClassLoader,其ucp
成员(URLClassPath
)包含URLClassPath.Loader
个实例的列表。在第一个方案中,它包含URLClassPath.FileLoader
和URLClassPath.JarLoader
。在第二种情况下,它只包含一个jar加载器。
就像java确定类路径条目无效并完全丢弃它一样。
这是为什么?我怎么能避免它?
更新 由于以下几个原因,我无法更改加载资源的机制:
创建自定义类加载器没问题,我只需要一些如何操作的指导。
我试过这个,但无法得到预期的结果:
import java.net.URL;
import java.net.URLClassLoader;
public class MyUrlClassLoader extends URLClassLoader {
public MyUrlClassLoader(ClassLoader parent) {
super(new URL[0], parent);
System.out.println("MyUrlClassLoader ctor");
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
System.out.println("url find class " + name);
return super.findClass(name);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.out.println("url load class " + name);
return super.loadClass(name);
}
@Override
public URL getResource(String name) {
System.out.println("url get resource " + name);
return super.getResource(name);
}
}
import java.net.URL;
public class ClassLoaderMain {
public static void main(String[] args) throws ClassNotFoundException {
URL url = ClassLoaderMain.class.getResource("/myfile.txt");
System.out.print("Loaded? ");
System.out.println(url != null);
System.out.println(ClassLoaderMain.class.getClassLoader().toString());
System.out.println(MyUrlClassLoader.class.getClassLoader().toString());
System.out.println(FakeClass.class.getClassLoader().toString());
}
}
当我运行java -cp . -Djava.system.class.loader=MyUrlClassLoader ClassLoaderMain
输出:
MyUrlClassLoader ctor
url load class java.lang.System
url load class java.nio.charset.Charset
url load class java.lang.String
url load class ClassLoaderMain
Loaded? true
sun.misc.Launcher$AppClassLoader@923e30
sun.misc.Launcher$AppClassLoader@923e30
sun.misc.Launcher$AppClassLoader@923e30
所以我的类加载器正在创建,并且正在调用load类,但它似乎不是它正在加载的类的类加载器?
答案 0 :(得分:0)
我最终通过创建自己的ClassLoader
来解决这个问题,从URLClassLoader派生。
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
public class CustomClassLoader extends URLClassLoader {
public CustomClassLoader(ClassLoader parent) {
// System classloader will filter inaccessible URLs.
// Force null parent to avoid using system classloader.
super(createURLReferences(), null);
}
/**
* Build an array of URLs based on the java.class.path property.
* @return An array of urls to search for classes.
*/
private static URL[] createURLReferences() {
String classpath = System.getProperty("java.class.path");
String[] classpathEntries = classpath.split(System.getProperty("path.separator"));
List<URL> urls = new ArrayList<URL>();
for (String classpathEntry : classpathEntries) {
File classpathFile = new File(classpathEntry);
URI uri = classpathFile.toURI();
try {
URL url = uri.toURL();
urls.add(url);
} catch (MalformedURLException e) {
System.out.println("Ignoring classpath entry: " + classpathEntry);
}
}
return urls.toArray(new URL[urls.size()]);
}
}