如何正确从 java 类路径中的网络目录加载资源?
我们的 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
因此正在创建我的类加载器,并且正在调用加载类,但它似乎不是正在加载的类的类加载器?
Our java application relies on some resources which are available on a network share. This network share is located on the classpath, and the resources are read at runtime using MyClass.class.getResourceAsStream("/myfile.jpg")
.
java -Djava.class.path=\\myserver\myshare:C:\myjar.jar MainClass
When the share is available at startup, everything runs smoothly. Image and properties files which are located in the share can be read using getResourceAsStream()
. However, if the share is not online when the application starts, even if the share comes online before any resources are read, they cannot be read using getResourceAsStream()
.
Doing some digging using eclispse + decompiler, I noticed one difference. The default classloader inherits from URLClassLoader, and its ucp
member (URLClassPath
) contains a list of URLClassPath.Loader
instances. In the first scenario, it contains a URLClassPath.FileLoader
and a URLClassPath.JarLoader
. In the second scenario, it only contains a jar loader.
It's like java determines that the classpath entry is invalid and completely discards it.
Why is this? How can I avoid it?
Update
I am unable to change the mechanism by which we are loading resources because of a few reasons:
- There are far too many areas which currently load files this way for me change at the moment
- There are situations where by the resource is actually being loaded by a third party component
I have no problem creating a custom class loader, I just need some guidance on how to do it.
I tried with this, but was unable to get expected results:
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());
}
}
When I run java -cp . -Djava.system.class.loader=MyUrlClassLoader ClassLoaderMain
This outputs:
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
So my class loader is being created, and load class is being called, but it doesn't appear to be the class loader for the classes it is loading?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我最终通过创建自己的从 URLClassLoader 派生的
ClassLoader
解决了这个问题。I ended up resolving this by creating my own
ClassLoader
, deriving from URLClassLoader.