2

(Да, это Hacky и, вероятно, не лучшая практика, но это наименее громоздкий раствор)Можно ли загрузить класс без загрузки ссылочных классов/импорта?

У меня есть проект, который включает в себя несколько банок - исполняемый гранатомет, сервер, обертка для сервера и плагин для сервера.

Launcher запускает оболочку, запуская новый несвязанный процесс, дочерний процесс или просто создавая его, в зависимости от конфигурации. Это должно быть неважно в отношении проблемы.

Обертка использует URLClassLoader для загрузки серверной банки и запуска ее, что отлично работает.

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

Проблема заключается в том, что загрузчик классов хочет автоматически разрешить каждый класс и импортировать в файлы классов плагинов patch, а сервер еще не загружен.

Мне нужно либо запретить загрузчику классов, либо импортировать классы после сервера, и заменить их уже загруженными классами. Насколько я знаю, второй вариант невозможно без нестабильности и манипуляции с байт-кодами?

+0

Просто, чтобы быть понятным о вашей проблеме, когда вы говорите * «Проблема в том, что загрузчик классов хочет автоматически разрешить каждый класс и импортировать в файлы классов плагинов patch, а сервер еще не загружен». *, Это означает что плагины плагины имеют зависимости от классов серверов, и поэтому загрузчик классов загружает сервер в результате загрузки плагинов, но вы не хотите, чтобы он загружал сервер, потому что это завинчивает всю вашу систему исправления, правильно? –

+0

Также это звучит как беспорядок; были, безусловно, лучшие подходы, которые можно было бы предпринять с самого начала, слишком поздно/невозможно реконструировать его немного? –

+1

Закрыть, но он не может загрузить сервер в этот момент, поэтому он просто бросает ClassNotFoundException. И переработайте его каким образом? На самом деле нет более простой альтернативы. –

ответ

0

Прежде всего, отвечая на ваш вопрос название:

Можно ли загрузить класс без загрузки ссылки классов/импорта?

Ну вы можете выбрать, чтобы не решимость класса пропускания ложного loadClass. Подробные сведения о том, что влечет за собой решение вопроса, можно найти here. Затем вы можете сделать разрешение в отдельном шаге, явно указав resolveClass.


Однако, если это не получить, что вы хотите, я не знаю, если это является единственно возможным решением, и это, конечно, ужасно (и были определенно более эффективные способы подойти к этому с самого начала), но что делать, если вы делаете что-то вроде этого:

Я собираюсь назвать ваши классы, которые служат патчами, и должен быть загружен перед серверами «pre-load» classes/code. Я собираюсь вызывать компоненты ваших патчей с зависимостями сервера, но загрузка которых должна быть отложена до тех пор, пока сервер не загрузит классы/код после загрузки.

Для каждого из ваших плагинов:

  1. Газа все после нагрузки вещи из класса патч и переместить его в другой класс, например PluginImplementation что ли. Затем сделайте экземпляр этого класса реализации членом вашего класса плагина, делегируя ему какие-либо необходимые ему функции-члены, , но не создавайте экземпляр PluginImplementation сразу же с места и введите поле члена типа Object (это часто описывается как an opaque pointer/the pimpl pattern). По сути, вы используете рефакторинг для использования идиомы pimpl, где ваш материал предварительной загрузки кодируется напрямую, а ваш материал после загрузки фактически делегируется другому классу, скрытому за Object, и не инициализируется немедленно.Ваша цель - удалить все зависимости от классов серверов из самого класса плагина, изменив его на голый минимум, необходимый для исправления, только загрузил, но переместил все мясо в класс реализации, непрозрачный указатель.

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

  3. Теперь ваши плагины разоблачить своего рода serverLoaded() или initializePlugin() метод или что-то подобное. После серверный класс загружает, просматривает и вызывает их на каждом загруженном плагине.

  4. Наконец, в методе инициализации из предыдущего шага, ваш плагин экземпляр пост-загрузки классов с помощью Class.forName().newInstance().

Так, в принципе, вы скрыть все ваши после загрузки материала за непрозрачным указателем, таким образом, удерживая ее скрытый от загрузчика классов, а затем, когда пришло время, динамически создавать экземпляры различных PluginImplementation классов, таким образом делая ваши плагины «полностью завершена», но позволяет задерживать зависящие от сервера компоненты.

Недостатком является то, что это добавляет несколько ограничений и требует большой заботы. Вы должны убедиться, что ни один из ваших PluginImplementation -delegated методов не вызывается до тех пор, пока не загрузится сервер и не будут вызваны функции инициализации, поскольку классы реализации еще не были созданы.

Я уверен, что могут быть лучшие варианты, но это тот, о котором я мог подумать, что, вероятно, связано с наименьшим количеством количество работы, учитывая то, что у вас уже есть. Вам нужно будет перемещать много кода; IDE, например Eclipse, или что-то другое, что может облегчить выплескивание делегатов по крайней мере (просто временно сделайте поле члена PluginImplementation, чтобы помочь IDE, а затем вы можете изменить его обратно до Object после генерации всего кода), но он должен минимизировать * фундаментальные изменения в вашей существующей архитектуре.


Вот еще одна идея, хотя я не уверен, насколько хорошо она вписывается в ваш текущий код, или, если это вообще возможно в вашей ситуации:

В принципе, цель здесь просто макияж плагины больше не будет зависеть от самого сервера, выполнив следующие действия:

  1. Объявить свой сервер в качестве интерфейса .
  2. Сделайте реализацию конкретного сервера реализации этого интерфейса.
  3. Измените все плагины для работы на этом интерфейсе, а не на экземпляре самого класса сервера.
  4. Убедитесь, что ваш класс сервера не объявляет о каких-либо внутренних классах, которые могут использовать плагины: сломайте любые внутренние классы на верхнем уровне (такие среды, как Eclipse, могут сделать это для вас).

Теперь вам нужно выяснить способ рассказать каждому плагину экземпляр сервера, с которым он работает, но плагин сохранит его в члене с типом базового интерфейса.

Таким образом, загрузка плагинов не будет загружать сам сервер, а только базовый интерфейс.

Я думаю, что эта идея намного проще и менее хакерской, чем выше, я просто не знаю, более или менее возможно, чем выше.


Обратите внимание, что оба из этих вариантов не обязательно guarantee success, но на практике они, вероятно, работать.

+0

Очень подробный ответ, но вы пропустили весь смысл того, что я пытаюсь сделать. Загружаемые патчи - _patches_, а не динамические плагины для API. Основной модуль плагинов загружается после сервера. Как будет загружаться «PluginImplmentation» перед классом сервера, который он должен заменить? Это не возможно. –

+0

@confusedpenguin О, но вы описали их как «плагины». Я добавил второй вариант и перепроектировал его как динамический API-интерфейс плагина - это один из вариантов редизайна, о котором вы спрашивали в вопросительном комментарии. Но этот второй вариант по-прежнему относится к теме динамического плагина. Как вы думаете, вы можете прояснить свой вопрос, чтобы описать, как именно вы исправляете серверный класс и что вы подразумеваете под «плагином»? –

+0

Я уже объяснил это как можно проще, и я просто буду ждать и спросить эксперта, поскольку никто, кажется, не полностью понимает проблему. Это так же просто, как _I нужно либо не разрешать загрузчику классов, либо импортировать классы после сервера, и заменять уже загруженные классы на них. Думаю, я научился не предоставлять никаких подробностей и только задайте прямой вопрос, хочу ли я получить ответ. TL; DR Если бы я хотел перепроектировать миллионы строк кода, чтобы исправить что-то такое простое, я бы не просил о помощи здесь. –

Смежные вопросы