Как модулировать приложение JSF/Facelets/Spring с OSGi?

Я работаю с очень большими приложениями JSF/Facelets, которые используют Spring для управления DI/bean. Мои приложения имеют модульную структуру, и в настоящее время я ищу подходы для стандартизации модульности.

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

  • Классы;
  • Статические ресурсы (изображения, CSS, скрипты);
  • Шаблоны Facelet;
  • Управляемые bean-компоненты - контексты приложений Spring с bean-компонентами запроса, сеанса и области приложения (альтернатива - управляемые bean-компоненты JSF);
  • Материал API сервлетов - сервлеты, фильтры, слушатели (это необязательно).

Чего я хотел бы избежать (почти любой ценой), так это необходимости скопировать или извлечь ресурсы модуля (например, шаблоны Facelets) в WAR или расширить web.xml для сервлетов, фильтров и т. д. модуля должно быть достаточно для добавления модуля (JAR, bundle, artifact, ...) в веб-приложение (WEB-INF/lib, bundles, plugins,...) расширить веб-приложение с помощью этого модуля.

В настоящее время я решаю эту задачу с помощью специального модуляризационного решения, основанного на использовании ресурсов classpath:

  • Сервлет специальных ресурсов обслуживает статические ресурсы из ресурсов classpath (JAR).
  • Специальный распознаватель ресурсов Facelets позволяет загружать шаблоны Facelet из ресурсов classpath.
  • Spring загружает контексты приложения через шаблон classpath*:com/acme/foo/module/applicationContext.xml - это загружает контексты приложения, определенные в JAR модуля.
  • Наконец, пара делегирующих сервлетов и фильтров делегируют обработку запросов к сервлетам и фильтрам, настроенным в контекстах приложения Spring от модулей.

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

  • Статические ресурсы - пакеты OSGi, которые хотят экспортировать статические ресурсы, регистрируют ResourceLoader экземпляры с контекстом связки. Центральный ResourceServlet использует эти загрузчики ресурсов для загрузки ресурсов из пакетов.
  • Шаблоны Facelet - аналогично выше, центральный ResourceResolver использует сервисы, зарегистрированные по пакетам.
  • Управляемые бины - я не знаю, как использовать такое выражение, как #{myBean.property} если myBean определяется в одной из связок.
  • API сервлетов - используйте что-то вроде WebExtender/Pax Web для регистрации сервлетов, фильтров и так далее.

Мои вопросы:

  • Я изобретаю велосипед здесь? Существуют ли стандартные решения для этого? Я нашел упоминание о Spring Slices, но не смог найти много документации об этом.
  • Как вы думаете, OSGi - подходящая технология для описанной задачи?
  • Является ли мой эскиз приложения OSGI более или менее правильным?
  • Как должны обрабатываться управляемые bean-компоненты (особенно область запроса / сеанса)?

Я был бы вообще благодарен за ваши комментарии.

5 ответов

Решение

То, что вы хотите сделать, звучит выполнимо, с несколькими оговорками:

Слой вида: во- первых, ваш слой вида звучит немного перегруженным. Существуют и другие способы модуляции компонентов JSF с использованием пользовательских компонентов, которые позволяют избежать головной боли, связанной с попыткой создать нечто столь же драматичное, как управляемые bean-компоненты с поздним связыванием.

Сами модули: во- вторых, ваши модули не кажутся особенно модульными. Ваш первый маркированный список звучит так, как будто вы пытаетесь создать совместимые веб-приложения, а не модули как таковые. Моя идея модуля состоит в том, что каждый компонент имеет четко определенную и более или менее дискретную цель. Как то, как экс лежит в основе vi. Если вы идете по маршруту OSGi, то мы должны определить модульность следующим образом: " Модульное", ради этого обсуждения, означает, что компоненты имеют "горячую" замену, то есть их можно добавлять и удалять, не нарушая приложение.

Зависимости: меня немного беспокоит ваше описание модулей как "возможно зависящих друг от друга". Вы, наверное, (я надеюсь) уже знаете это, но ваши зависимости должны сформировать ациклический ориентированный граф. Как только вы вводите циклическую зависимость, вы просите обидеть мир с точки зрения возможной ремонтопригодности приложения. Одним из самых больших недостатков OSGi является то, что он не предотвращает циклические зависимости, так что вам нужно обеспечить это. В противном случае ваши зависимости будут расти как кудзу и постепенно душат остальную часть экосистемы вашей системы.

Сервлеты: Fuhgeddaboudit. Вы не можете позднее связывать сервлеты с веб-приложением, пока не будет запущена спецификация Servlet 3.0 (как указал Паскаль). Чтобы запустить отдельный служебный сервлет, вам нужно поместить его в собственное приложение.


Хорошо, так много для предостережений. Давайте подумаем о том, как это может работать:

Вы определили свой собственный модуль JSF, чтобы делать... что именно? Давайте дадим ему определенную, довольно тривиальную цель: экран входа в систему. Итак, вы создаете свой экран входа в систему, позднее связываете его с помощью OSGi в своем приложении и... что дальше? Как приложение узнает о функциональности входа в систему, если вы не определили ее на своей странице.jspx? Как приложение узнает, что оно находится там, где оно не может знать?

Есть способы обойти это, используя условные включения и тому подобное (например, <c:if #{loginBean.notEmpty}>), но, как вы сказали, все становится немного странно, когда ваш управляемый loginBean существует в другом модуле, который, возможно, еще даже не был введен в приложение. Фактически, вы получите исключение сервлета, если этот loginBean не существует. Ну так что ты делаешь?

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

Мне нужно уделить немного времени, чтобы указать, что я не подхожу к этой проблеме. Не за что. Учитывая что-то вроде простой страницы входа или даже такой сложной, как график акций, я лично предпочел бы создать собственный компонент JSF. Но если требование "я хочу, чтобы мои управляемые bean-компоненты были модульными (т. Е. С возможностью горячей замены и т. Д.)", Это единственный известный мне способ заставить его работать. И я даже не совсем уверен, что это сработает. Этот обмен электронной почтой предполагает, что это проблема, над которой разработчики JSF только начали работать.

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

Но, похоже, многое из того, с чем вы работаете, это сама логика представления - например, необходимость поменять местами другой шаблон представления. OSGi/Spring должна быть в состоянии помочь, но вам нужно что-то в вашем приложении, чтобы выбрать между доступными реализациями: почти то, для чего был создан OSGi Service Registry.

Это оставляет статические ресурсы. Вы можете модулировать их, но помните, что вам нужно определить интерфейс для извлечения этих ресурсов, и вам нужно будет обеспечить реализацию по умолчанию, чтобы ваше приложение не задыхалось, если они отсутствуют. Если i18n является соображением, это может быть хорошим способом. Если вы хотите быть по- настоящему авантюрным, вы можете поместить свои статические ресурсы в JNDI. Это сделало бы их полностью горячей заменой и избавило бы вас от необходимости пытаться решить, какую реализацию использовать программно, но есть некоторые недостатки: любой неудачный поиск приведет к тому, что ваше приложение вызовет исключение NamingException. И это излишне. JNDI обычно используется в веб-приложениях для конфигурации приложений.

Что касается ваших оставшихся вопросов:

Я изобретаю велосипед здесь? Существуют ли стандартные решения для этого?

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

Как вы думаете, OSGi - подходящая технология для описанной задачи?

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

Является ли мой эскиз приложения OSGI более или менее правильным?

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

Но не верьте мне на слово. Я нашел другие материалы для чтения в этих местах.

И так как вы спрашиваете о Spring Slices, этого должно быть достаточно, чтобы вы начали. Вам понадобится Gi t-клиент, и, похоже, вы будете изучать приложение, просматривая исходный код. И это очень ранний прототип кода.

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

  1. пока что нет хорошо интегрированного решения между Web-контейнером и платформой OSGi.
  2. OSGi может быть слишком сложным для пользовательского веб-приложения, которое просто ищет простую модульную архитектуру. Я бы рассмотрел OSGi, если мой проект должен поддерживать сторонние расширения, которые не находятся под нашим 100-процентным контролем, если проект нуждается в горячих повторных развертываниях, строгих правилах доступа между плагинами и т. Д.

Индивидуальное решение, основанное на загрузчиках классов и фильтрах ресурсов, кажется мне очень подходящим. В качестве примера вы можете изучить исходный код Hudson или проект Java Plug-in Framework (JPF) (http://jpf.sourceforge.net/).

Что касается расширения web.xml, нам может повезти со спецификацией Servlet 3.0 (http://today.java.net/pub/a/today/2008/10/14/introduction-to-servlet-3.html#pluggability-и-расширяемость).

"Фрагмент дескриптора развертывания веб-модуля" (он же web-фрагмент.xml), представленный в спецификации Servlet 3.0, был бы неплох. Спецификация определяет это как:

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

Java EE 6 может быть не вариант для вас сейчас, хотя. Тем не менее, это будет стандартизированное решение.

Enterprise OSGi - это довольно новый домен, поэтому не думайте, что вы получите решение, которое непосредственно удовлетворяет ваши потребности. Тем не менее, одна из вещей, которые я обнаружил отсутствующими в Equinox (движок osgi за Eclipse и, следовательно, с самой большой базой пользователей!), - это согласованная конфигурация / DI-сервис. Недавно в моем проекте возникли аналогичные потребности, и мы завершили создание простой службы конфигурации osgi.

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

Помимо конфигурации, вы можете взглянуть на недавно выпущенную книгу Equinox для получения инструкций по использованию OSGi в качестве основы для создания модульных приложений. Примеры могут быть специфическими для Equinox, но принципы будут работать с любой средой OSGi. Ссылка - http://equinoxosgi.org/

Вам следует взглянуть на Spring DM Server (он переводится на Eclipse Virgo, но еще не выпущен). В недавно выпущенной корпоративной спецификации OSGi есть много хорошего.

Я думаю, что некоторые из учебников Spring DM помогут. Но да, можно загружать ресурсы и классы извне веб-пакета, используя стандартную модульность. В этом, это хорошо подходит.

Что касается контекста сеанса - он обрабатывается так, как вы ожидаете в сеансе. Однако вы можете столкнуться с проблемами при совместном использовании этого сеанса между веб-пакетами до такой степени, что не будете уверены, что это вообще возможно.

Вы также можете использовать один веб-пакет, а затем использовать, например, реестр расширений Eclipse для расширения возможностей вашего веб-приложения.

Другие вопросы по тегам