Понимание концепций OSGi. Попробуйте следовать подходу головоломки
Опубликовано: 2013-04-20Сегодня OSGi
стал очень популярным благодаря своему модульному подходу и способности устанавливать логические границы между модулями. Когда мы обнаруживаем это впервые, возникает вопрос, с чего начать понимать, как это работает?
Чтобы понять концепции OSGi, мы попытаемся следовать подходу головоломки, идея состоит в том, чтобы начать с тривиальной части этой технологии и искать другие части, связанные с найденными. А собрать пазл нам поможет JArchitect, который поможет обнаружить внутренний дизайн OSGi.
Чтобы быть более конкретным, мы анализируем с помощью JArchitect приложение, использующее технологию OSGi, это относится к известной IDE eclipse, которая использует равноденствие контейнера OSGi.
Начнем с типичного определения OSGi:
OSGi снижает сложность, предоставляя модульную архитектуру для современных крупномасштабных распределенных систем, а также для небольших встроенных приложений. Построение систем из собственных и готовых модулей значительно снижает сложность и, следовательно, затраты на разработку и обслуживание. Модель программирования OSGi реализует перспективность компонентных систем.
Тривиальная часть OSGi — это модульность, давайте узнаем, что такое модули OSGi?
Модули OSGI называются пакетами, поэтому каждое приложение состоит как минимум из одного пакета.
Эти пакеты выполняются внутри контейнера, и поскольку каждый модульный подход, когда контейнер управляет модулями, возникает вопрос, какой контракт должен реализовывать каждый модуль, чтобы быть интегрированным в контейнер?
Возьмем в качестве примера связку org.eclipse.equinox.jsp.jasper и найдем все ее реализованные интерфейсы, для этого мы можем выполнить следующий запрос CQLinq:
1 2 3 4 |
from t in Types where t . ParentProject . Name ==” org . eclipse . equinox . jsp . jasper_1 . 0.300.v20110502 “ let interfaces = t . InterfacesImplemented from i in interfaces select i |
Реализован интерфейс BundleActivator из пакета OSGi, этот интерфейс содержит два метода start и stop, полезные для настройки запуска и остановки пакета.
Еще одной особенностью пакета является его файл манифеста, вот часть файла манифеста org.eclipse.equinox.jsp.jasper:
1 2 3 4 5 6 7 8 9 |
Manifest - Version : 1.0 Bundle - Localization : plugin Bundle - RequiredExecutionEnvironment : CDC - 1.0 / Foundation - 1.0 , J2SE - 1.3 Bundle - SymbolicName : org . eclipse . equinox . jsp . jasper Eclipse - LazyStart : true Eclipse - SourceReferences : scm : cvs : pserver : dev . eclipse . org : / cvsroot / rt : org . eclipse . equinox / server - side / bundles / org . eclipse . equinox . jsp . jaspe r ; tag = v20110502 Bundle - Activator : org . eclipse . equinox . internal . jsp . jasper . Activator |
Как мы видим, этот манифест содержит некоторую метаинформацию, необходимую контейнеру, например, указание класса активатора пакета, который реализует интерфейс BundleActivator.
Пакет представляет собой первую часть головоломки, и вот упрощенное представление пакета:
И просто чтобы иметь представление обо всех бандлах, используемых eclipse, давайте найдем все классы, реализующие интерфейс BundleActivator.
1 2 |
from t in Types where t . Implement ( “ org . osgi . framework . BundleActivator “ ) select new { t , t . NbBCInstructions } |
Кто управляет пакетом и вызывает методы BundleActivator?
Чтобы обнаружить это, давайте найдем методы, прямо или косвенно вызывающие BundleActivator.start.
1 2 3 4 |
from m in Methods let depth0 = m . DepthOfIsUsing ( “ org . eclipse . osgi . framework . internal . core . BundleContextImpl . startActivator ( BundleActivator ) “ ) where depth0 > = 0 orderby depth0 select new { m , depth0 } |
Пакет активируется платформой OSGi при запуске. Класс фреймворка запускается контейнером равноденствия. И чтобы лучше понять, что происходит при запуске контейнера, вот некоторые действия, выполняемые при запуске контейнера:
Когда контейнер запускается, он инициализирует фреймворк OSGi, фреймворк получает все установленные бандлы, для каждого создает экземпляр класса BundleHost и сохраняет в репозиторий найденный бандл.
Класс BundleHost реализует интерфейс Bundle, который содержит такие методы, как запуск, остановка, удаление и обновление. Эти методы необходимы для управления жизненным циклом пакета.
Итак, наша вторая часть головоломки — контейнер OSGi, он запускается с помощью Equinoxlauncher, который инициализирует фреймворк. Класс фреймворка отвечает за загрузку пакетов и их активацию.
После знакомства с некоторыми базовыми понятиями о пакетах и контейнерах давайте углубимся внутрь пакетов и узнаем, как они работают внутри.
Возьмем в качестве примера пакет org.eclipse.equinox.http.servlet и найдем методы, вызываемые методом запуска его класса Activator.
Этот пакет создает службу и регистрирует ее в контейнере. Служба в OSGi определяется стандартным классом или интерфейсом Java. Обычно интерфейс Java используется для определения интерфейса службы. Служба является предпочтительным методом, который пакеты должны использовать для связи друг с другом.

Вот несколько полезных сценариев использования сервисов:
- Экспорт функций из пакета в другие пакеты.
- Импорт функций из других пакетов.
- Зарегистрируйте прослушиватели для событий из других пакетов.
Еще одно замечание из предыдущего графика зависимостей заключается в том, что для создания экземпляра службы используется фабрика служб.
Наша третья часть головоломки - это уровень сервисов OSGi, каждый пакет может использовать или объявлять некоторые сервисы, что обеспечивает подход к проектированию компонентов, вот новое представление пакета OSGi.
Если пакет использует службы для связи с другими пакетами, как он взаимодействует с другими банками?
Если мы разработаем пакет и попытаемся использовать класс из другого jar, мы можем быть удивлены тем, что он не будет работать должным образом, причина в том, что ClassLoader перехватывается контейнером OSGi, чтобы проверить, что давайте искать, какой метод вызывает java. язык.Thread.setContextClassLoader.
1 2 |
from m in Methods where m . IsUsing ( “ java . lang . Thread . setContextClassLoader ( ClassLoader ) “ ) select new { m , m . NbBCInstructions } |
Его вызывают многие методы, включая EquinoxLauncher. поэтому каждый раз, когда пакет пытается создать экземпляр класса, контейнер OSGi будет проверять, разрешено ли коду выполнять это действие или нет, и здесь появляется роль импортированного и экспортированного пакета в файле манифеста.
1 2 3 4 |
Export - Package : org . eclipse . equinox . http . servlet ; version =” 1.1.0 ″ Import - Package : javax . servlet ; version =” 2.3 ″ , javax . servlet . http ; version =” 2.3 ″ , org . osgi . framework ; version =” 1.3.0 ″ , org . osgi . service . http ; versi on =” [ 1.2 , 1.3 ) ” |
Пакет объявляет явно экспортированный и импортированный пакет, и чтобы проверить это, давайте найдем пакеты, используемые пакетом org.eclipse.equinox.http.servlet, и проверим, использует ли он только импортированный пакет.
1 2 |
from n in Packages where n . IsUsedBy ( “ org . eclipse . equinox . http . servlet_1 . 1.200.v20110502 “ ) select new { n , n . NbBCInstructions } |
Как мы видим, все используемые пакеты указаны в файле манифеста в разделе импорта пакетов.
Однако экспортированный пакет представляет собой пакет, который можно использовать из других пакетов. он представлен интерфейсом ExportedPackage, и мы можем искать классы контейнеров, используя этот интерфейс.
1 2 |
from t in Types where t . IsUsing ( “ org . osgi . service . packageadmin . ExportedPackage “ ) select new { t , t . NbBCInstructions } |
Что интересно с этой новой возможностью, так это то, что пакет будет иметь четко определенные границы, и то, что он использует и что он предоставляет в качестве сервисов, очень четко определено.
Мы можем принудительно проверить использование импортированных пакетов с помощью других инструментов, например, с помощью CQLinq мы можем написать некоторые правила, предупреждающие каждый раз, когда проект использует пакеты, отличные от указанных, но лучше иметь эту проверку в среде выполнения, чтобы разработчик нельзя нарушать эти правила.
Эта возможность обрабатывать импортированные и экспортированные пакеты управляется уровнем модулей OSGi, и это была наша четвертая часть головоломки.
Давайте вернемся к контейнеру OSGi и выясним, какие сервисы он предоставляет?
Контейнерные услуги
Как мы обнаружили перед запуском контейнера классом EquinoxLauncher, а класс фреймворка инициализирует и запускает пакеты, чтобы определить, какие службы предоставляются, давайте найдем все классы, используемые в методе инициализации фреймворка.
1 2 |
from t in Types where t . IsUsedBy ( “ org . eclipse . osgi . framework . internal . core . Framework . initialize ( FrameworkAdaptor ) “ ) select new { t , t . NbBCInstructions } |
Некоторые классы уже обнаружены ранее, например BundleRepository, BundleHost, PackageAdminImpl и ServiceRegistry.
А как насчет других классов:
- Начальный уровень менеджера:
Каждый пакет OSGi связан с начальным уровнем, который позволяет серверу управлять относительным порядком запуска и остановки пакетов. Активными должны быть только пакеты, начальный уровень которых меньше или равен активному начальному уровню серверной платформы. Обычно пакет с меньшим начальным уровнем обычно запускается раньше. - БезопасностьАдминистратор:
Уровень безопасности обрабатывает аспекты безопасности, ограничивая функциональность пакета заранее определенными возможностями. - Менеджер по корпоративным мероприятиям:
Служба администратора событий предоставляет модель публикации-подписки для обработки событий. Это реализовано в соответствии со спецификацией службы администрирования событий OSGi. Служба администрирования событий распределяет события между издателями событий и подписчиками событий (обработчиками событий), вставляя канал событий. Издатели публикуют события в канале, а канал событий определяет, какие обработчики должны быть уведомлены. Таким образом, издатели и обработчики не имеют прямого знания друг о друге, что упрощает управление событиями.
Полная картина OSGi
Соберем все описанные ранее кусочки пазла, и у нас получится следующая OSGi-картинка:
Эта архитектура имеет следующие интересные преимущества:
- Простой.
- Уменьшенная сложность.
- Простое развертывание.
- Безопасный.
Что делает его очень привлекательным и достойным обхода, и вы не потратите зря свое время, если изучите его подробно.