Я создаю клиент-серверное приложение. Клиент запускает небольшой загрузчик, который загружает клиент в виде jar модуля, но только если файл client.jar изменился. Затем загрузчик пытается запустить клиент через ServiceLoader.
Вот код, который запускает поставщика услуг в клиентском банке.
static PokerGameInstance getPokerGame() {
URL[] urls = null;
try {
urls = new URL[] { Paths.get("client.jar").toUri().toURL() };
System.out.println(urls[0]);
}
catch (Exception e) {
System.out.println("Could not create URL[] to use to create " +
"ClassLoader for client.jar.jar.");
return null;
}
URLClassLoader classLoader;
try {
classLoader = new URLClassLoader(urls);
}
catch (Exception e) {
System.out.println("Could not create classloader for " +
"client.jar.");
return null;
}
try { // Test code
classLoader.loadClass("com.brandli.jbpoker.client.PokerGame");
}
catch (ClassNotFoundException e) {
System.out.println("Could not find PokerGame class");
}
ServiceLoader<PokerGameInstance> loader = ServiceLoader
.load(PokerGameInstance.class, classLoader);
Optional<PokerGameInstance> optional = loader.findFirst();
if (optional.isEmpty()) {
System.out.println("Could not load client service provider.");
return null;
}
return optional.get();
}
При первом запуске нет client.jar. Другой код загружает client.jar, а затем запускается приведенный выше код. Просматривая выходные данные этого метода, URLClassLoader может загрузить класс поставщика услуг (который называется PokerTable). Однако ServiceLoader ничего не находит, и метод выводит «Не удалось загрузить поставщика услуг клиента».
Однако при втором запуске client.jar уже существует, а fre sh - нет. скачал. В этом случае ServiceLoader возвращает правильный класс, и все работает.
Я использую путь к модулю, который включает в себя весь каталог jar-файлов. Там же загружается Client.jar. Итак, во втором запуске система ClassLoader выбирает client.jar. Другими словами, второй проход работает не потому, что ServiceLoader получает client.jar из URLClassLoader. Я проверил это, выполнив второй запуск с параметром ClassLoader для ServiceLoader.load (), для которого установлено значение null.
Я также изменил путь к модулю, включив в него только дискретные файлы jar, чтобы система ClassLoader не принимала клиента .jar, если это там. В этом случае приведенный выше код всегда завершается ошибкой.
В результате ServiceLoader не распознает службу в client.jar, даже если URLClassLoader загрузит объект. Это не имеет ничего общего с загружаемым client.jar, потому что проблема существует, даже если client.jar существует с самого начала (если не обнаружен системой ClassLoader).
Помните, что client.jar является модулем баночка. Код выше находится в модуле, который имеет эту информацию модуля. java:
module com.brandli.jbpoker.loader {
exports com.brandli.jbpoker.loader;
requires transitive javafx.controls;
requires transitive com.brandli.jbpoker.core;
uses com.brandli.jbpoker.loader.PokerGameInstance;
}
Client.jar имеет эту информацию модуля. java:
module com.brandli.jbpoker.client {
requires transitive javafx.controls;
requires transitive com.brandli.jbpoker.core;
requires transitive com.brandli.jbpoker.loader;
requires transitive com.brandli.jbpoker.common;
provides com.brandli.jbpoker.loader.PokerGameInstance with
com.brandli.jbpoker.client.PokerGame;
}
I подозреваю, что это как-то связано с модулями. У кого-нибудь есть идеи?