null

Thick vs Thin WAR и что использовать в современном Liferay

При разработке порталов на базе Liferay (и не только их) рано или поздно приходится столкнуться с выбором между двумя разными архитектурными подходами Thick WAR («толстый» war) и Thin WAR («тонкий» war). Эти понятия характеризуют тот способ, которым создается архив веб-приложений, определяя, как именно упаковываются зависимости, что критически влияет на скорость деплоя, потребление памяти и стабильность серверов приложений, будь то легковесный Tomcat или модульный WildFly. Разберем суть обоих подходов, их плюсы, минусы и то, как они уживаются с OSGi-контейнером современного Liferay.

Суть вопроса

Главное отличие между этими подходами кроется в вопросе, где лежат сторонние библиотеки (JAR-файлы), нужные для работы приложения Thick WAR собирается по принципу «все необходимые зависимости должны лежать в том же архиве». Все тяжелые библиотеки (например, Spring, JSF, PrimeFaces) упаковываются прямо внутрь архива в папку WEB-INF/lib. На выходе получается тяжелый файл размером в несколько десятков мегабайт. Thin WAR же подразумевает почти пустую папку WEB-INF/lib. Все сторонние библиотеки объявляются как provided (то есть должны быть предоставлены приложению средой исполнения) и деплоятся в Liferay один раз в виде глобальных модулей. Сам WAR-файл содержит только скомпилированный код и весит, как правило, меньше мегабайта.

А как в Liferay?

Во время деплоя .war-файла в Liferay сервер не запускает архив напрямую. Внутри Liferay работает специальный инструмент – WAB Generator (Web Application Bundle), который трансформирует классический веб-архив в понятный для OSGi-контейнера модуль. И вот тут начинается разница в поведении серверов. При тонком подходе все общие библиотеки загружаются в память OSGi-контейнера (osgi/modules) только один раз. Портлет в своем конфигурационном файле указывает импорты нужных пакетов, а серверу не нужно создавать новые сущности в памяти, поскольку все портлеты смотрят на одни и те же разделяемые библиотеки. Деплой же становится быстрым. При толстом подходе в каждом из .war файлов в WEB-INF/lib будет лежать своя копия PrimeFaces и JSF-библиотек. Сервер приложений будет вынужден создать изолированный ClassLoader для каждого архива. В итоге в оперативной памяти сервера десятки одинаковых классов могут дублироваться, что приводит к огромному расходу RAM, долгому парсингу файлов при деплое и высокому риску поймать OutOfMemoryError. Поэтому, если используется Thick WAR, то выгоднее всегда упаковывать все портлеты в один war архив, тогда тяжелые Jakarta-версии PrimeFaces и JSF-мостов загрузятся в память в единственном экземпляре, не занимая лишнюю память, а все портлеты внутри этого WAR будут использовать общие классы.

Стоит также учитывать особенности используемого сервера приложений. С Apache Tomcat больше шансов, что все заведется «из коробки», поскольку Tomcat изолирует WEB-INF/lib WAR-файла, берет оттуда библиотеки и запускает портлеты. WildFly же представляет собой полноценный Jakarta EE сервер, у которого есть собственная встроенная подсистема JSF. Если просто задеплоить «толстый» WAR, библиотеки внутри архива начнут конфликтовать с библиотеками самого WildFly, и сервер упадет с ошибкой ClassCastException.Чтобы Thick WAR заработал на WildFly, придется принудительно изолировать серверный JSF, разбираться с настройками сервера и конфигурацией jboss-deployment-structure.xml.

Что же выбрать?

В современной разработке под Liferay идеальный путь – это уход от WAR в сторону чистых OSGi JAR-модулей. Но если нужен именно .war (например, при миграции старого проекта), то нужно помнить следующее:

  • Thick WAR – это большой размер артефактов, хранение всех зависимостей в том же архиве, больше ресурсов и времени деплоя, зато потенциально решает возможные проблемы с отсутствием нужных зависимостей во время исполнения приложения.
  • Thin WAR – это легковесное решение, которое делегирует хранение зависимостей OSGI, ускоряя деплой, но (возможно) требующее для сборки собственноручного добавления зависимостей в OSGI контейнер

 

 

 

 

Next