Как использовать реализацию, загруженную с другим загрузчиком классов Java?

Я пишу библиотеку, где я позволяю людям предоставлять реализации определенных интерфейсов с использованием инфраструктуры плагинов (это JPF, если вы знакомы). Плагины не хранятся в пути к классам. Фреймворк дает мне ClassLoader для каждого плагина, поэтому, когда запрашивается реализация с именем "MyImpl" интерфейса "MyInterface", я могу найти правильный плагин, а затем использовать ClassLoader этого плагина для загрузки класса, из которого я могу сделать экземпляр если я что-то знаю о конструкторе. Все идет нормально.

Однако теперь у меня есть случай, когда мне нужно вызвать метод, который доступен только в этой конкретной реализации. Итак, есть два способа сделать это:

Способ 1:

// Makes sure that MyImpl has been loaded, using the custom classloader
Plugins.getClass(MyInterface.class, "MyImpl");
// This line will not compile because MyImpl is not available at build time
MyImpl foo = new MyImpl();
// If I could get this far, this line would work:
foo.methodOnlyInMyImpl();

Способ 2:

// This call will get an instance of MyImpl (already written and tested)
MyInterface foo = Plugins.getInstance(MyInterface.class, "MyImpl");
// Compiler error because there is no MyInterface.methodOnlyInMyImpl method.
foo.methodOnlyInMyImpl()

Метод 1 является более чистым из них, так как он наиболее похож на то, как вы бы написали код, если бы класс был "нормальным" и не был доступен через плагин. Однако ни один из них не компилируется.

Варианты, которые я придумала до сих пор:
A. Используйте метод 2, но используйте рефлексию для вызова метода methodOnlyInMyImpl (пожалуйста, нет!)
B. Поместите классы плагинов в путь сборки, а затем используйте метод 1, который будет компилироваться. (мой нынешний фаворит)
C. B +, когда плагины установлены, скопируйте файлы классов в другой каталог, который находится в пути к классам, чтобы системный загрузчик классов мог их загрузить (вызывает другие проблемы).

Итак, мои вопросы:

  1. Я пропускаю другую идею, которая лучше?
  2. Если я сделаю B, будут ли у меня проблемы во время выполнения? В конце концов, класс, использующий MyImpl, предположительно будет загружен с помощью системного загрузчика классов. Итак, как только он увидит MyImpl fooне попытается ли он загрузить MyImpl с помощью системного загрузчика классов, что приведет к сбою (даже если вызов Plugins.newInstance предоставит экземпляр MyImpl)?

2 ответа

Решение

Во-первых, какое преимущество вы получаете от механизма плагинов, когда вам нужно реализовать его против реальной реализации? Плагин должен реализовывать интерфейс, и вы можете использовать реализацию через интерфейс.

Я не похож на JPF, но Java-классы никогда не совместимы при загрузке различными загрузчиками классов. Но есть два возможных пути:

  1. Интерфейс находится в вашем загрузчике классов, плагин classloader имеет ваш загрузчик классов в качестве родителя, поэтому его интерфейс такой же, как у вас. Код 2 должен работать с этим, когда метод объявлен в интерфейсе.

  2. Вы можете использовать сериализацию. Это ограниченный способ более полезной передачи объектов данных между независимыми загрузчиками классов. Мне нужно было использовать это для межконтекстной диспетчеризации с параметром запроса между двумя веб-приложениями.

Есть библиотека TransLoader, которая упоминалась в предыдущем вопросе. Вот URL источника: http://code.google.com/p/transloader/.

Другие вопросы по тегам