Как расширить путь модуля во время выполнения - PullRequest
0 голосов
/ 17 января 2019

Мне нравятся услуги. Мне также нравится модульная система. К сожалению для меня, до того, как я использовал Java 9, я привык получать поставщиков услуг из jar-файлов, загружаемых во время выполнения через URLClassLoader, что-то вроде этого (для краткости я буду использовать Java 10's var):

var url = new File("myjar.jar").toURI().toURL();
var cl = new URLClassLoader(new URL[] {url}, getClass().getClassLoader());
var services = ServiceLoader.load(MyService.class, cl);
for (var service : services) {
  ...
}

Это прекрасно работает, даже в Java 9 и более поздних версиях, но загружает jar в classpath, что означает, что он использует старый метод META-INF\services для поиска поставщиков услуг. Я бы предпочел использовать метод module-info, но для этого требуется, чтобы вместо файла jar загружался путь к модулю, но я не мог найти какой-либо способ сделать это. Итак, я надеюсь, что кто-то здесь, кто лучше разбирается в модульной системе, расскажет мне, как это можно сделать (или нет, если это так).

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Оказывается, я использовал неправильные параметры командной строки (я не знал, что не должен использовать java -jar с модульными банками). Используя правильные команды, ответ @ Holger сработал, за исключением того, что набор, переданный Configuration.resolve, должен содержать все имена загружаемых модулей, что было достаточно легко исправить:

var path = Path.of("myjar.jar");
var cl = new URLClassLoader(new URL[]{path.toUri().toURL()});
var mf = ModuleFinder.of(path);
var cfg = Configuration.resolve(mf, List.of(ModuleLayer.boot().configuration()), mf, mf.findAll().stream().map(module -> module.descriptor().name()).collect(Collectors.toSet()));
var ml = ModuleLayer.defineModulesWithOneLoader(cfg, List.of(ModuleLayer.boot()), cl).layer();
var services = ServiceLoader.load(ml, MyService.class);
services.forEach(System.out::println);
0 голосов
/ 17 января 2019

Самый маленький рабочий пример, который я смог собрать, это

var path = Path.of("myjar.jar");
var cl = new URLClassLoader(new URL[]{path.toUri().toURL()});
var mf = ModuleFinder.of(path);
var cfg = Configuration.resolve(mf, List.of(ModuleLayer.boot().configuration()), mf, Set.of());
var ml = ModuleLayer.defineModulesWithOneLoader(cfg, List.of(ModuleLayer.boot()), cl).layer();
var services = ServiceLoader.load(ml, MyService.class);
services.forEach(System.out::println);

Предполагается, что myjar.jar является модульным jar, заявляющим о предоставлении MyService реализаций.

...