Статьи

Есть ли место для OSGi в разработке корпоративных приложений? (Часть 2)

В части 1Сегодня, в заключительной части, он завершает свой аргумент о применимости OSGi на предприятии.
В первой части он обсудил проблемную область OSGi. Там он объяснил проблемы, связанные с динамическим управлением классами и как OSGi реагирует на эти проблемы. В этой заключительной части он рассматривает две другие проблемные области, обрисованные ранее: отсутствие контроля версий классов Java и отсутствие модульности в контексте адского пути к классам. Как OSGi заполняет эти пробелы? Наконец, насколько готов OSGi для реального использования? Аслам также отвечает на этот вопрос.
Гертьян Виленга, лидер зоны JavaLobby

Управление версиями классов

Пакет не является особым артефактом в OSGi. Это просто JAR с дополнительными заголовками в манифесте. Например:

# Indentification headers
Bundle-SymbolicName: org.sample.MyService
Bundle-Version: 1.0.1
Bundle-Name: Sample Service
Bundle-Vendor: Samples, Inc.

# Class Path
Bundle-ClassPath: .

# Bundle Lifecycle management
Bundle-Activator:org.sample.MyServiceActivator

# Dependencies
Import-Package: org.osgi.framework;version=1.3
Require-Bundle: org.sample.AnotherService;bundle-version=”[1.2.0,2.0.0)”

# Exports
Export-package: org.sample.MyService

Обратите внимание, что каждый пакет в этих заголовках также указывает диапазон версий. Внимательно присмотревшись, обратите внимание также на наличие заголовка манифеста для версии комплекта. Когда происходит связывание между пакетами, диапазоны версий используются для разрешения действительных привязок. На рисунке 1 класс foo работает одновременно в двух версиях. Версия foo 1.0.0 экспортируется пакетом A, а версия foo 2.0.0 экспортируется пакетом C. Однако пакет B зависит только от версии 1.0.0 foo и, таким образом, привязан только к ней.

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

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

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

модульность

Модульность — это обманчивая проблема. Можно было бы подумать, что это давнее требование было бы взломано давным-давно. В нетривиальных, но относительно простых приложениях добиться модульности не сложно. Самым простым способом достижения модульности в простых приложениях является использование горизонтальной модульности, которая отображается непосредственно на слои в стеке приложений. Например, в приложении, которое реализует шаблоны Model-View-Controller и Object Access, типовые модули состоят из классов моделей, классов представлений, классов контроллеров и классов DAO.

На каждом из этих уровней (или модулей) будут экспортированы интерфейсы и развернуты пакеты, специфичные для реализации, для выполнения этих зависимых интерфейсов. Преимущество этого в OSGi заключается в том, что можно переключать, например, реализацию Hibernate интерфейса DAO с реализацией iBatis того же интерфейса DAO. Опять же, это делается динамически, пока остальная часть приложения еще работает.

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

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

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

Одним из подходов к обнаружению модулей является использование стратегического дизайна от Domain Driven Design (DDD). В стратегическом дизайне создаются ограниченные контексты в проблемной области и определяются точки соприкосновения между контекстами. Это на самом деле искаженное использование ограниченных контекстов, потому что ограниченный контекст может быть переведен в другой ограниченный контекст, в котором содержимое контекста могло быть преобразовано в процессе перевода. Тем не менее, стратегический дизайн является разумной отправной точкой для создания модулей. Это происходит на довольно высоком уровне в архитектуре и дает модули, которые являются относительно крупнозернистыми, но тесно связаны с проблемной областью.

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

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

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

Часто модули создаются в самом начале проекта, отражая общие части системы, и в основном остаются нетронутыми. Это не так уж далеко от подхода «массовый дизайн базы данных, который невозможно изменить». Обычно внутренние компоненты модуля могут со временем меняться, но фактический набор модулей редко меняется. DDD поощряет рефакторинг модуля. Это более болезненно, чем рефакторинг классов, но сборка модулей во время выполнения, обратная совместимость и возможности управления версиями классов в OSGi открывают путь для постепенного рефакторинга модулей по мере развития системы.

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

Можете ли вы использовать OSGi в своих приложениях сегодня?

Без сомнения, да! OSGi является зрелой и предлагает архитекторам и разработчикам программного обеспечения возможность решить некоторые сложные проблемы. Динамический характер среды выполнения OSGi, ее отличные возможности управления версиями классов и встроенный реестр сервисов модулей для обнаружения зависимостей создают экосистему для разработки на основе POJO, которая является высокопроизводительной для корпоративных проектов.

Подпроект Spring Framework Dynamic Modules for OSGi еще больше упрощает разработку OSGi, используя знакомый контекст приложения Spring для регистрации сервисов и определения зависимостей между пакетами, используя знакомую инверсию Spring контейнера управления / внедрения зависимостей.

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

Однако OSGi повредила и некоторые проверенные решения. Наиболее заметным является аспект ориентации. Внутри связки АОП легко достижим. Тем не менее, применение аспектов в пакетах все еще остается проблемой, и такие проекты, как проект Eclipse Equinox Aspect, демонстрируют большие перспективы.

В целом, OSGiTM — динамическая модульная система для Java, заслуживает внимания, которое она получает. С формированием рабочей группы OSGi для предприятий она, безусловно, будет укрепляться в краткосрочной и среднесрочной перспективе. Он определенно достоин своего места в пространстве разработки корпоративных приложений.

Ресурсы