У меня есть веб-служба, которую мы назовем service.war. Он реализует интерфейс, который мы назовем ServicePluginInterface. Во время запуска service.war он считывает переменные среды и использует их для поиска jar-файла (MyPlugin.jar). Когда он находит эту банку, он затем использует вторую переменную среды для загрузки плагина в банку. Класс, который он загружает, выглядит так:
public class MyPlugin implements ServicePluginInterface {...}
Сервлет пытается загрузить плагин, используя такой код:
try {
if (pluginClass == null) {
plugin = null;
}
else {
ZipClassLoader zipLoader = new ZipClassLoader(Main.class.getClassLoader(), pluginJar);
plugin = (ServicePluginInterface)zipLoader.loadClass(pluginClass).newInstance();
plugin.getAccount(null,null);
}
} catch (Exception e) {
...
}
Хитрость в том, что у меня нет исходного кода или jar-файла для ServicePluginInterface. Не желая так легко сдаваться, я вытащил файлы классов из файлов service.war. Используя эти файлы классов в качестве зависимостей, я смог без предупреждений компилятора создать MyPlugin. Однако, когда на самом деле выполняется Tomcat, приведенный выше раздел кода генерирует исключение времени выполнения:
java.lang.ClassCastException: com.whatever.MyPlugin cannot be cast to com.whomever.ServicePluginInterface
В качестве второй точки отсчета я также могу создать синтетический загрузчик классов (отдельный исполняемый файл Java, который использует тот же механизм загрузки классов. Опять же, поскольку у меня нет исходного источника для ServicePluginInterface, я использовал файлы классов из WAR Этот второй, синтетический загрузчик, или, если хотите, фальшивый сервлет, МОЖЕТ загрузить MyPlugin очень хорошо.Поэтому я бы предположил, что Tomcat JVM, похоже, обнаруживает некоторую разницу между классами, найденными внутри WAR, и извлеченными файлами классов. Однако, поскольку все, что я сделал для извлечения файлов классов, - это открыть WAR в виде zip-архива и скопировать их, трудно представить, что это может быть.
Хавьер сделал полезное предложение об удалении определения ServicePluginInterface, проблема с этим решением заключалась в том, что ZipClassLoader, который сервлет использует для загрузки подключаемого модуля из jar-файла, переопределяет функцию ClassLoader findClass для извлечения класса из JAR следующим образом:
protected Class<?> findClass(String name) throws ClassNotFoundException
{
ZipEntry entry = this.myFile.getEntry(name.replace('.', '/') + ".class");
if (entry == null) {
throw new ClassNotFoundException(name);
}
...
}
Затем класс ZipClassLoader рекурсивно загружает все родительские объекты и интерфейсы из jar . Это означает, что если jar-файл плагина не содержит определения для ServicePluginInterface, он завершится ошибкой.
1 ответ
Классы, определенные разными загрузчиками классов, разные :
Во время выполнения может быть несколько ссылочных типов с одним и тем же двоичным именем. загружаются одновременно разными загрузчиками классов. Эти типы могут или может не представлять одно и то же объявление типа. Даже если два таких типа делают представляют одно и то же объявление типа, они считаются разными. JLS
В этом случае zipLoader
возвращает экземпляр MyPlugin
, который реализует другое ServicePluginInterface
(загружается ли он тоже из zip-архива?):
(ServicePluginInterface)zipLoader.loadClass(pluginClass).newInstance();
Кажется, что сервер приложений уже имеет определение ServicePluginInterface
, поэтому вам не нужно его повторно развертывать. Этого должно быть достаточно, чтобы добавить необходимые файлы (ServicePluginInterface
и т. Д.) Как неразвернутые зависимости вашего проекта.
Другой подход заключается в том, чтобы жить с фактом и обращаться к методам в ServicePluginInterface
через отражение (используйте объект Class
, возвращаемый zipLoader
, вместо ServicePluginInterface.class
).
Похожие вопросы
Новые вопросы
java
Java - это язык программирования высокого уровня. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег редко используется отдельно и чаще всего используется вместе с [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] и [maven].