Как правильно загрузить ресурсы из сетевого каталога в пути к классам Java? - PullRequest
2 голосов
/ 21 июля 2011

Наше 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 определяет, что запись classpath недействительна, и полностью ее отбрасывает.

Почему это? Как я могу избежать этого?

Обновление Я не могу изменить механизм загрузки ресурсов по нескольким причинам:

  1. Слишком много областей, в которых в данный момент загружаются файлы, поэтому я могу изменить в данный момент
  2. Существуют ситуации, когда ресурс фактически загружается сторонним компонентом

У меня нет проблем с созданием пользовательского загрузчика классов, мне просто нужно несколько советов, как это сделать.

Я пытался с этим, но не смог получить ожидаемый результат:

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

Итак, мой загрузчик классов создается и вызывается класс загрузки, но он не является загрузчиком классов для загружаемых классов?

1 Ответ

0 голосов
/ 28 июля 2011

Я решил эту проблему, создав собственную 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()]);
    }
}
...