Реализация Osgi На Платформе Karaf



ОСГИ – это не сложно Я много раз встречал мнение, что OSGI — это сложно.

Более того, я сам когда-то придерживался такого мнения.

Если быть точным, то 2009 год. В то время мы собирали проекты с помощью Maven Tycho и разворачивали их в Equinox. И это действительно было сложнее, чем разрабатывать и собирать проекты для JavaEE (на тот момент только появилась версия EJB 3, на которую мы перешли).

Equinox был гораздо менее удобен по сравнению, например, с Weblogic, а преимущества OSGI для меня тогда не были очевидны.

Но потом, много лет спустя, на новой работе мне пришлось взяться за проект, который был задуман на базе Apache Camel и Apache Karaf. Это была не моя идея, о Кэмеле я к тому времени знал уже давно, и решил прочитать о Карафе, даже не имея еще предложения.

Прочитал однажды вечером и понял — вот оно, простое и готовое, практически то же решение некоторых задач стандартного JavaEE, подобное которому я когда-то делал на коленке с помощью Weblogic WLST, Jython и Maven Aether. Итак, допустим, вы решили попробовать OSGI на платформе Karaf. С чего начать?



Если вы хотите более глубокого понимания

Вы, конечно, можете начать с чтения документации.

А может с Хабра — тут были довольно хорошие статьи, скажем так, довольно давно.

так .

Но в целом карафу до сих пор уделяется незаслуженно мало внимания.

Было еще пару отзывов этот или этот .

Здесь Этот Упоминание о карафе лучше пропустить.

Как говорится, не читайте по ночам советские газеты.

потому что вам скажут, что караф - это рамки ОСГИ - так что не верьте.

OSGI-фреймворки — это Apache Felix или Eclipse Equinox, на базе которых работает караф.

Вы можете выбрать любой из них.

Следует отметить, что когда упоминается Jboss Fuse, или Apache ServiceMix, это следует читать как «Караф, с предустановленными компонентами», т.е.

по сути — то же самое, только собранное производителем.

Я бы не советовал начинать с этого на практике, но вы также можете прочитать обзорные статьи, например, о ServiceMix. Для начала я попытаюсь здесь очень кратко определить, что такое OSGI и для чего его можно использовать.

По большому счету OSGI — это инструмент для создания Java-приложений из модулей.

Близким аналогом можно считать, например, JavaEE, причем в некоторой степени OSGI-контейнеры могут выполнять модули JavaEE (скажем, веб-приложения в виде War), а с другой стороны, многие JavaEE-контейнеры содержат внутри себя OSGI, как средство реализации модульности «под себя»» То есть JavaEE и OSGI схожи с точки зрения совместимости, и успешно дополняют друг друга.

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

В случае с OSGI модуль называется бандлом, и представляет собой известный всем разработчикам jar-архив с некоторыми дополнениями (то есть здесь он очень похож, например, на войну или ухо).

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

Метаданные пакета — это знакомый META-INF/MANIFEST.MF. Заголовки манифеста OSGI не пересекаются с заголовками JRE; следовательно, вне контейнера OSGI пакет представляет собой обычный jar. Важно, чтобы среди метаданных были:

  
  
  
  
  
  
  
  
   

Bundle-SymbolicName: com.example.myosgi Bundle-Version: 1.0.0

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

По аналогии с JavaEE, жизненный цикл пакетов выглядит следующим образом:

Реализация OSGI на платформе Karaf

Помимо сервисов, пакеты также могут импортировать и экспортировать пакеты (пакеты в обычном Java-понимании этого термина).

«Экспортированные пакеты определяются внутри пакета и становятся доступными для других компонентов, когда пакет установлен в системе.

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

Импорт пакетов может быть объявлен необязательным, как и импорт услуг.

И еще немаловажно, что импорт и экспорт содержат указание версии (или диапазона версий).



Отличия от JavaEE

Что ж, хорошо, что они похожи – мы поняли.

Насколько они разные? На мой взгляд, главное отличие в том, что OSGI дает нам гораздо больше гибкости.

Как только пакет перешел в состояние STARTED, возможности ограничиваются только вашим воображением.

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

Контейнер не берет на себя управление всеми ресурсами в такой степени, как JavaEE. Вы можете экспортировать новые услуги во время работы.

Попробуйте, скажем, динамически создать новый сервлет в JavaEE? Но тут вполне возможно, более того, контейнер сервлетов karaf, созданный на базе jetty, сразу обнаружит ваш созданный сервлет, и он будет доступен клиентам по определенному URL. Хотя это небольшое упрощение, если приложение JavaEE в его классическом виде состоит в основном из компонентов:

  • пассивный, ожидающий звонка от клиента
  • определяется статически, то есть во время развертывания приложения.

С другой стороны, приложение на базе OSGI может содержать:
  • активные и пассивные компоненты, которые работают по расписанию, выполняют опрос, слушают сокет и т. д.
  • сервисы могут определяться и публиковаться динамически
  • вы можете подписываться на события фреймворка, например, прослушивать регистрацию сервисов, пакетов и т. д., получать ссылки на другие пакеты и сервисы и делать многое другое.

Да, в JavaEE многое из этого тоже частично возможно (например, через JNDI), но в случае с OSGI на практике это проще.

Хотя, вероятно, здесь есть еще несколько рисков.



Отличия карафа от чистого OSGI

Помимо фреймворка, караф включает в себя массу полезных вещей.

По сути, караф — это инструмент для удобного управления OSGI-фреймворком — установки туда бандлов (в том числе групп), их настройки, мониторинга, описания ролевой модели и обеспечения безопасности и тому подобное.



Давай уже потренируемся?

Ну что ж, начнем сразу с установки.

Тут особо писать нечего - заходим на сайт karaf.apache.org, скачиваем дистрибутив, распаковываем.

Версии karaf отличаются поддержкой разных спецификаций OSGI (4, 5 или 6) и версий Java. Я не рекомендую семейство 2.x, но можно использовать 3 (если у вас Java 8, как у меня), и 4, хотя сейчас разрабатывается только семейство 4.x (текущая версия — 4.2.2, он поддерживает OSGI 6 и Java до 10).

Karaf неплохо работает под Windows и Linux; все необходимое для создания сервиса и автозапуска имеется.

Также заявлена поддержка MacOS и многих других типов Unix. Обычно караф можно начать сразу, если вы находитесь в Интернете.

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

Конфигурация карафа находится в папке etc дистрибутива.

Имена файлов конфигурации не слишком очевидны, но в данном случае вам понадобится файл org.ops4j.pax.url.mvn.cfg. Формат этого файла — свойства Java. Вы можете установить репозиторий либо в самом файле конфигурации, указав список URL-адресов в настройках, либо просто указав, где находится ваш файл settings.xml. Там Караф возьмет местоположение вашего прокси, которое обычно необходимо знать в интранете.

Кафару нужно несколько портов, это HTTP, HTTPS (если настроен веб, а не по умолчанию), SSH, RMI, JMX. Если они у вас заняты или вы хотите запустить несколько копий на одном хосте, вам придется их тоже поменять.

Всего таких портов около пяти.

Порты типа jmx и rmi находятся здесь: org.apache.karaf.management.cfg, ssh — org.apache.karaf.shell.cfg, для смены портов http/https нужно будет создать (его скорее всего не существует) etc/ файл org.ops4j.pax.web.cfg и пропишите в него значение org.osgi.service.http.port=нужный вам порт. Тогда уж точно можно запускать, и как правило все запустится.

Для промышленного использования вам, очевидно, придется внести изменения в файл bin/setenv, или bin/setenv.bat, например, для выделения необходимого объема памяти, но для начала это смотреть не обязательно.

Вы можете запустить Караф сразу с консоли, с помощью команды karaf или в фоновом режиме с помощью команды запуска сервера, а затем подключиться к нему по SSH. Это совершенно стандартный SSH с поддержкой SCP и SFTP. Вы можете выполнять команды и копировать файлы туда и обратно.

Вполне возможно подключиться к любому клиенту, например мой любимый инструмент — Far NetBox. Вы можете войти в систему, используя свой логин и пароль, а также с помощью ключей.

В jsch потроха, со всеми вытекающими последствиями.

Рекомендую сразу завести дополнительное консольное окно для просмотра логов, которые находятся в data/log/karaf.log (да и другие файлы обычно там есть, хотя это настраивается).

Логи вам пригодятся; не все понятно из коротких сообщений в консоли.

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

Установка hawtio осуществляется с помощью двух команд из консоли karaf ( как описано здесь ), и увы, сегодня версия karaf 3.x больше не поддерживается (придется поискать более старые версии hawtio).

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



Ладно, началось, что дальше?



Реализация OSGI на платформе Karaf

Собственно, чего вы ожидали? Я сказал тебе, что это будет ssh. Таб работает, если что.

Пришло время установить какое-нибудь приложение.

Приложение OSGI либо представляет собой пакет, либо состоит из нескольких пакетов.

Караф может развертывать приложения в нескольких форматах:

  • Бандл в виде jar, как с манифестом OSGI, так и без него.

  • xml, содержащий Spring DM или Blueprint
  • xml, содержащий так называемую фичу, которая представляет собой набор бандлов, других фич и ресурсов (конфигурационных файлов)
  • архив .

    kar, содержащий несколько функций и репозиторий maven с зависимостями

  • Приложения JavaEE (при некоторых дополнительных условиях), например .

    war

Это можно сделать несколькими способами:
  • поместите приложение в папку развертывания
  • установить из консоли с помощью команды install
  • установить функцию с помощью команды из консоли Feature:install
  • Кар: установить
Ну в целом это очень похоже на то, что умеет типичный JavaEE-контейнер, но несколько удобнее (я бы сказал, гораздо удобнее).



Простая банка

Самый простой вариант – установить обычную банку.

Если он у вас есть в репозитории maven, то для установки достаточно команды:

install mvn:groupId/artifactId/version

При этом Караф понимает, что это обычная банка, и обрабатывает ее, создавая на лету пакетную обертку, т. н.

оболочка, генерирующая манифест по умолчанию с импортом и экспортом пакетов.

Обычно нет смысла устанавливать только jar, так как этот бандл будет пассивным — он экспортирует только те классы, которые будут доступны другим бандлам.

Этот метод используется для установки таких компонентов, как Apache Commons Lang, например:

install mvn:org.apache.commons.lang3/commons-lang/3.8.1

Но не получилось :) Вот правильные координаты:

install mvn:org.apache.commons/commons-lang3/3.8.1

Посмотрим, что произошло: list -u покажет нам пакеты и их источники:

karaf@root()> list -u START LEVEL 100 , List Threshold: 50 ID | State | Lvl | Version | Name | Update location ------------------------------------------------------------------------------------------------- 87 | Installed | 80 | 3.8.1 | Apache Commons Lang | mvn:org.apache.commons/commons-lang3/3.8.1 88 | Installed | 80 | 3.6.0 | Apache Commons Lang | mvn:org.apache.commons/commons-lang3/3.6

Как видите, вполне возможно установить две версии одного компонента.

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



Контекст Jar и Spring

Если у вас внутри jar есть Spring Context, все становится интереснее.

Karaf Deployer автоматически ищет контексты xml в папке META-INF/spring и создает их, если все внешние пакеты, необходимые для пакета, были успешно найдены.

Таким образом, все сервисы, которые были внутри контекстов, уже запустятся.

Если, например, у вас там был Camel Spring, то тоже начнутся маршруты Camel. Это означает, что, скажем, службу REST или службу, прослушивающую TCP-порт, вы уже можете запустить.

Конечно, запустить несколько сервисов, слушающих один порт, не так уж и просто.



Просто контекст Spring XML

Если у вас были, например, определения источников данных JDBC внутри контекста Spring, вы можете легко установить их в Karaf отдельно.

Те.

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

Контекст будет запущен стандартным способом.

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

Их необходимо экспортировать в OSGI как сервисы.

Подробнее об этом чуть позже.



Весенний ДМ

В чем фактическая разница между Spring DM (версией с поддержкой OSGI) и классическим Spring? Потому что в классическом случае все бины в контексте создаются на этапе инициализации контекста.

Новые не могут появиться, старые не уйдут. В случае OSGI можно устанавливать новые пакеты и удалять старые.

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

Способ реагирования называется услугами.

Сервис обычно представляет собой интерфейс со своими методами, который публикуется каким-то бандлом.

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

Метаданные — это простой набор свойств «ключ-значение».

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

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

Сборка запускается только после разрешения ссылок на сервисы.

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

Те.

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

Позвольте мне отметить, что сервис — это любой интерфейс (или вы можете публиковать только классы), поэтому вы можете легко опубликовать java.util.Map с данными как сервис.

Помимо прочего, сервис позволяет указать метаданные, а ссылка позволяет осуществлять поиск сервиса по этим метаданным.



План

Blueprint — это новая версия Spring DM, которая немного проще.

А именно, если в Spring у вас есть кастомные XML-элементы, то их здесь нет, за ненадобностью.

Иногда это все же доставляет неудобства, но, честно говоря, не часто.

Если вы не переносите проект из Spring, вы можете сразу начать с Blueprint. Суть здесь та же — это XML, описывающий компоненты, из которых собирается контекст бандла.

Для тех, кто знает Spring, здесь вообще нет ничего незнакомого.

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

<Эxml version="1.0" encoding="UTF-8"?> <blueprint xmlns=" http://www.osgi.org/xmlns/blueprint/v1.0.0 "> <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource"> <property name="URL" value="URL"/> <property name="user" value="USER"/> <property name="password" value="PASSWORD"/> </bean> <service interface="javax.sql.DataSource" ref="dataSource" id="ds"> <service-properties> <entry key="osgi.jndi.service.name" value="jdbc/ds"/> </service-properties> </service> </blueprint>

Что ж, мы развернули этот файл в папке развертывания и посмотрели результаты команды list. Мы увидели, что бандл не запустился — у него статус Indtalled. Пробуем запустить и получаем сообщение об ошибке.

Пакет теперь указан как Неудачный.

В чем дело? Очевидно, что ему также нужны зависимости, в данном случае Jar с классами Oracle JDBC, а точнее пакет oracle.jdbc.pool. Находим в репозитории нужный jar, либо скачиваем его с сайта Oracle, и устанавливаем, как описано ранее.

Наш источник данных запустился.

Как всем этим воспользоваться? Ссылка на сервис вызывается в справочнике Blueprint (где-то, в контексте другого бандла):

<reference id="dataSource" interface="javax.sql.DataSource"/>

Затем этот bean-компонент, как обычно, становится зависимостью для других bean-компонентов (в примере с Camel-sql):

<bean id="sql" class="org.apache.camel.component.sql.SqlComponent"> <property name="dataSource" ref="dataSource"/> </bean>



Баночка и активатор

Канонический способ инициализации пакетов — использование класса, реализующего интерфейс Активатора.

Это типичный интерфейс жизненного цикла, содержащий методы запуска и остановки, которые передаются контекст .

Внутри них бандл обычно запускает свои потоки, при необходимости начинает прослушивать порты, подписывается на внешние сервисы с помощью OSGI API и так далее.

Это, пожалуй, самый сложный, самый простой и самый гибкий метод. Мне это не понадобилось ни разу за три года.



Настройки и конфигурация

Понятно, что такая конфигурация DataSource, как показана в примере, мало кому нужна.

Логин, пароль и т. д. — все жестко закодировано внутри XML. Эти параметры необходимо вывести наружу.



<property name="url" value="${oracle.ds.url}"/> <property name="user" value="${oracle.ds.user}"/> <property name="password" value="${oracle.ds.password}"/>

Решение довольно простое и похоже на то, что используется в классическом Spring: в определенный момент жизненного цикла контекста значения свойств подставляются из различных источников.

На этом первая часть завершается.

Если будет интерес к этой теме, будет продолжение.

Мы рассмотрим, как собирать приложения из бандлов, настраивать, отслеживать и автоматически развертывать системы на этой платформе.

Теги: #java #osgi karaf Camel Java

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.