Пользовательский Tomcat Webapp ClassLoader - PullRequest
4 голосов
/ 26 декабря 2010

Я пытаюсь реализовать собственный загрузчик классов для tomcat.Моя первая попытка привела к исключению приведения класса (очевидно, tomcat пытается привести мой загрузчик к org.apache.catalina.loader.WebappLoader).Хорошо, я расширил WebappLoader и добавил catalina.jar в мой путь сборки.

Теперь я готов к развертыванию (я думаю).Я получаю эту ошибку:

SEVERE: Catalina.start: LifecycleException: start:: java.lang.NoClassDefFoundError: org / apache / catalina / loader / WebappLoader

Tomcat поставляется с catalina.jar для запуска, так что я на 99,9% уверен, что он уже загружен в Tomcat.Я проверил это, проверив /server/lib/catalina.jar, который содержит apache WebappLoader.Кроме того, ручное связывание другого файла catalina.jar создает целый беспорядок, как и ожидалось.

Я в замешательстве.Любые советы будут горячими.

Спасибо!

Обновление: Интересно, что то же самое на tomcat6 (расширение WebappLoader; работает на tomcat5.5), все еще вызывает исключение ClassCastException.Похоже, что класс, выполняющий приведение, был загружен с использованием загрузчика, отличного от того, который загружал мой класс.Во всяком случае, я не понимаю, как бы я мог контролировать это, разве что где-то еще может отсутствовать конфигурация tomcat?Есть идеи для tomcat6?

Ответы [ 2 ]

5 голосов
/ 27 декабря 2010

Может быть, я плотный, но я думаю, что это должен быть WebappClassLoader, а не WebappLoader.Импорт выглядит нормально, хотя.

1 голос
/ 27 декабря 2010

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

Сценарий таков:

  1. Загрузчик (собственно JVM / Tomcat / любой другой) загружает ваш код
  2. Ваш загрузчик классов загружает ваши добавления, недоступные в указанном выше пути к классам.
  3. Ваш код ссылается на эти добавления.
  4. Эти дополнения недоступны в том же пространстве имен, что и код, загруженный загрузчиком.
  5. Ваш код в пространстве имен загрузчика запускается, пытается ссылаться на код в вашем пользовательском пространстве имен, и этоне виден из пространства имен загрузчика.Таким образом, в этот момент JVM завершается с ошибкой NoClassDefFound.

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

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

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

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

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

Пример:

@MyCustomAnnotation(implementation="my.custom.package.MyImpl")
public class MyFeatureProvider {
  public MyFeature getFeature() { // return an instance of MyImpl here }
}

Обратите внимание, что поскольку класс MyFeatureProvider будет загружен раньше, чем MyImpl, ваш загрузчик классов будет заранее знать оаннотация в MyFeatureProvider, поэтому он сможет переопределить модель делегирования по умолчанию для MyImpl.Поскольку остальная часть вашего кода взаимодействует только с MyImpl как экземпляр MyFeature, родительский загрузчик никогда не должен блокировать при виде неопределенных символов - и ошибка ClassNoDefFound устранена.

...