如何从java类路径中的网络目录正确加载资源?

时间:2011-07-21 19:39:10

标签: java runtime classpath classloader

我们的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.FileLoaderURLClassPath.JarLoader。在第二种情况下,它只包含一个jar加载器。

就像java确定类路径条目无效并完全丢弃它一样。

这是为什么?我怎么能避免它?

更新 由于以下几个原因,我无法更改加载资源的机制:

  1. 目前有太多的区域正在以这种方式加载文件
  2. 在某些情况下,资源实际上是由第三方组件加载的
  3. 创建自定义类加载器没问题,我只需要一些如何操作的指导。

    我试过这个,但无法得到预期的结果:

    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类,但它似乎不是它正在加载的类的类加载器?

1 个答案:

答案 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()]);
    }
}