Доступ к ресурсам из другого файла jar

У меня есть простая структура: файл jar данных, содержащий пакет данных, и файл службы jar, который запускает службу с использованием данных. Чтобы упростить замену данных, я их разделяю, а classpath путь service.jar содержит каталог, в котором находится data.jar.

Внутри service.jar я использую getResource для загрузки файлов данных. Это работает, если файлы данных находятся непосредственно в папке, но не выполняется, когда они находятся внутри data.jar;

Это не удается:

all
+ globalclasspath
| + data.jar
|   + mine.properties
+ daemons
  + service.jar

jsvc -cp globalclasspath:daemons/service.jar (...)

MyClass.class.getClassLoader( ).getResource( "mine.properties" ); // <-- null

Но это работает:

all
+ globalclasspath
| + mine.properties
+ daemons
  + service.jar

jsvc -cp globalclasspath:daemons/service.jar (...)

MyClass.class.getClassLoader( ).getResource( "mine.properties" ); // <-- not null

Я не хочу изменять путь к классам (если только я не могу изменить его на нечто общее, которое не зависит от имени файла данных jar), но я в порядке с изменением строки getResource (я try/data/mine.properties и /data.jar/mine.properties безрезультатно). Есть ли какое-то изменение, которое я могу сделать, чтобы ресурсы могли быть загружены из контейнера?

Ответ 1

Решение 1

Используйте подстановочный шаблон для классов.

jsvc -cp globalclasspath/*:daemons/service.jar (...)

См. "Как использовать подстановочный знак в пути к классам для добавления нескольких банок?"

Решение 2

Чтобы читать данные в JAR не по пути к классам, используйте URLClassLoader. Общий алгоритм таков:

  • Найдите список JAR в каталоге globalclasspath.
  • Создайте URLClassLoader из этого списка JAR.
  • Найдите нужный ресурс из экземпляра URLClassLoader.

Чтобы найти JAR в пути к классам, я использовал ResourceList статью StackOverflow "Получить список ресурсов из classpath.

public class MyClass {
    /**
     * Creates a {@code URLClassLoader} from JAR files found in the
     * globalclasspath directory, assuming that globalclasspath is in
     * {@code System.getProperty("java.class.path")}.
     */
    private static URLClassLoader createURLClassLoader() {
        Collection<String> resources = ResourceList.getResources(Pattern.compile(".*\\.jar"));
        Collection<URL> urls = new ArrayList<URL>();
        for (String resource : resources) {
            File file = new File(resource);
            // Ensure that the JAR exists
            // and is in the globalclasspath directory.
            if (file.isFile() && "globalclasspath".equals(file.getParentFile().getName())) {
                try {
                    urls.add(file.toURI().toURL());
                } catch (MalformedURLException e) {
                    // This should never happen.
                    e.printStackTrace();
                }
            }
        }
        return new URLClassLoader(urls.toArray(new URL[urls.size()]));
    }

    public static void main(String[] args) {
        URLClassLoader classLoader = createURLClassLoader();
        System.out.println(classLoader.getResource("mine.properties"));
    }
}

Я выполнил следующую команду:

java -cp globalclasspath:daemons/service.jar MyClass

Выход терминала:

jar:file:/workspace/all/globalclasspath/data.jar!/mine.properties