Я пишу библиотеку, где я разрешаю людям предоставлять реализации определенных интерфейсов, используя плагиновую фреймворк (это JPF, если вы знакомы). Плагины не сохраняются в пути к классам. Структура предоставляет мне ClassLoader для каждого плагина, поэтому, когда запрашивается реализация с именем MyImpl интерфейса «MyInterface», я могу найти правильный плагин, а затем использовать этот классный загрузчик плагина для загрузки класса, из которого я могу создать экземпляр если я знаю что-то о конструкторе. Все идет нормально.Как использовать реализацию, загруженную разным загрузчиком классов Java?
Однако теперь у меня есть случай, когда мне нужно вызвать метод, доступный только для этой конкретной реализации. Итак, есть два способа, я мог бы попытаться сделать это:
метод 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 + при установке плагинов, копировать файлы классов в другой каталог, который находится в пути к классам, так что система Загрузчик классов может загрузить их (вызывает другие проблемы)
Итак, мои вопросы:
- Я пропустил еще одну идею, которая лучше?
- Если я сделаю B, у меня будут проблемы во время выполнения? В конце концов, класс, использующий MyImpl, предположительно, был бы загружен с помощью системного загрузчика. Итак, как только он увидит
MyImpl foo
, не будет ли он пытаться загрузить MyImpl с помощью системного загрузчика классов, что не удастся (даже если вызов Plugins.newInstance предоставит экземпляр MyImpl)?
Пример, иллюстрирующий преимущество: у меня есть интерфейсы X и Y. Существует метод X.getY(), который возвращает Y. У меня есть четыре плагина, которые предоставляют реализации Xa и Xb и Y реализации Yc и Yd. Теперь Xa и Xb должны использовать внутреннюю реализацию Yc, поэтому мне нужна конкретная реализация. Приложение может просто взаимодействовать с Xs и Ys, но плагины нуждаются в конкретных реализациях. JPF помогает управлять зависимостями плагина. –
+1 - ОП пытается игнорировать контракт, подразумеваемый использованием интерфейсов. Если плагины являются единственными, которые заботятся о классах реализации, тогда он/она должен будет предоставить доступ к классу реализации во время компиляции, использовать листинг и обработать возможное исключение ClassCastException. – kdgregory
К сожалению, я не могу предвидеть все интерфейсы. Сериализация (Arne), кастинг во время выполнения (kdgregory) и TransLoader (Carl) требуют, чтобы класс был каким-то образом доступным в текущем загрузчике классов, что не в моем случае - оно сводилось к использованию рефлексии или предъявлению требований к времени выполнения classpath для включения плагинов. Я выбрал последний. Принимая этот ответ из-за ключевой фразы, «классы Java никогда не совместимы при загрузке разными загрузчиками классов». Спасибо, я бы добавил +1, если бы у меня был представитель. –