开发者

How do I correctly load resources from a network directory in the java classpath?

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:

  1. There are far too many areas which currently load files this way for me change at the moment
  2. 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开发者_StackOverflow 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?


I ended up resolving this by creating my own ClassLoader, deriving from 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()]);
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜