OSGi является спецификацией, и наиболее распространенными реализациями можно считать Equinox , Apache Felix и Knoplerfish . В этой статье я попытаюсь привести пример создания простого пакета OSGi в Equinox .
Структура OSGi
Базовую структуру OSGi можно увидеть на рисунке справа. Реализации OSGi находятся на вершине JVM и предоставляют механизмы для управления службами, определения компонентов, выполнения, управления и контроля жизненного цикла модулей. Наиболее важные концепции OSGi описаны ниже:
Bundle
В системах OSGi компонентам, которые создают структуру, присваивается имя « Bundle ». На этапе развертывания каждый пакет OSGi представляет собой файл JAR . Но основное отличие файлов jar-пакетов с обычными можно считать определением манифеста для OSGi и некоторыми классами для OSGi. Мы обсудим эти различия в следующих разделах и в примере.
Сервисы
Сервисы обеспечивают взаимодействие между узлами структуры. Сервисы представляются как интерфейсы и регистрируются в реализации, которая выполняет этот интерфейс. Параллельно со структурой SOA наличие доступа через сервисы OSGi делает системы на основе OSGi более свободными по сравнению с обычными jav-структурами на основе jar. Эта структура также позволяет изменять компоненты системы во время выполнения.
OSGi реализует сервисный каталог для сервисов, которые должны быть зарегистрированы и доступны через. OSGi также предоставляет механизмы управления сервисами.
Жизненный цикл
OSGi предоставляет платформу, которая позволяет контролировать жизненный цикл комплектов. В этой структуре каждый пакет имеет свою собственную конфигурацию OSGi, в основном с точки зрения зависимостей и открытых частей, и система управляется самой OSGi. OSGi знает комплекты, которые составляют систему, которая предоставляется с файлом конфигурации с заказом, и управление жизненным циклом применяется для каждого из компонентов с данным заказом. Сторона пакета управления жизненным циклом управляется классом «Activator», который реализует интерфейс OSGi, который должен существовать в каждом «обычном» пакете OSGi. (Не для «фрагментированных», но пока это выходит за рамки данной статьи, забудьте об этом)
Связки
Как упомянуто выше, b undle — это файл jar, который имеет по крайней мере класс Activator и файл MANIFEST, в котором есть специфичные для OSGi заголовки и информация. Образец файла MANIFEST можно увидеть ниже. Давайте посмотрим на значение каждой части в определении.
1
2
3
4
5
6
7
8
|
Bundle-Name: Our Bundle Bundle-SymbolicName: us.elron.bundles.ours Bundle-Description: Very own bundle of ours Bundle-ManifestVersion: 1 Bundle-Version: 1.0.0 Bundle-Activator: us.elron.bundles.ours.BundleActivator Export-Package: us.elron.bundles.ours.exported; version = "1.0.0" Import-Package: us.elron.bundles.yours.exported; version = "1.3.0" |
- Bundle-Name : «привлекательное для публики» имя пакета.
- Bundle-SymbolicName: как единственное обязательное определение в файле MANIFEST, символическое имя определяет уникальное имя пакета в экосистеме OSGi. Поскольку это определение должно быть уникальным, оно обычно определяется как имя базового пакета для данного соглашения.
- Описание пакета : описание «raison d’être» пакета.
- Bundle-ManifestVersion: версия манифеста пакета.
- Bundle-Version: версия пакета OSGi.
- Bundle-Activator: этот класс используется для управления жизненным циклом пакета. Этот класс вызывается OSGi для запуска или остановки пакета.
- Export-Package. В этом разделе определяются пакеты, которые должны использоваться другими пакетами.
- Import-Package: пакеты, необходимые для выполнения текущего пакета, определены в этом разделе.
Жизненный цикл
Структура OSGi обеспечивает необходимые механизмы для управления жизненным циклом комплектов. Пакеты подлежат OSGi для контроля их жизненных циклов в соответствии с заданной конфигурацией. Этапы жизненного цикла подробно объясняются ниже:
СОСТАВЛЯЮЩИЙ СТАТУС
|
ОПИСАНИЕ
|
---|---|
УСТАНОВЛЕНЫ
|
Это состояние указывает, что шаг установки был успешно завершен. В этом случае не выполняется ни анализ зависимостей, ни загрузка классов. Выполняются только необходимые шаги, такие как определение свойств пакета, анализируя его файл манифеста. |
ПОСТАНОВИЛИ
|
Пакет находится в этом состоянии, когда OSGi разрешает и удовлетворяет все свои зависимости и выполняет операции загрузки классов. Это состояние, которое наступает до запуска и после остановки. |
ЗАПУСК
|
Это состояние, в котором пакет обнаружен, когда вызывается метод «start» Активатора пакета, но еще не завершенный успешно или неудачно. |
ACTIVE
|
Пакет успешно запущен и работает, что означает, что метод «Activator» привел к успеху. |
ОСТАНОВКА
|
Это состояние, в котором пакет обнаружен, когда вызывается метод «стоп» Активатора пакета, но еще не завершенный успешно или неудачно. |
Uninstalled
|
Это состояние, когда пакет удаляется из системы. В этой ситуации нет перехода в другое состояние. Компонент должен быть установлен снова. |
Давайте сделаем простой пример, чтобы прояснить упомянутые концепции и шаги выше. В нашем примере будет два пакета, один из которых предоставляет службу генератора случайных чисел для генерации случайных чисел, а другой пакет будет использовать эту службу для печати случайного числа каждую секунду с отдельным процессом. (Не имеет смысла? То же самое для меня, но достаточно, чтобы понять концепции )
Теперь давайте разработаем этот пример проекта (желательно) вместе, используя Eclipse и Equinox.
В Eclipse комплекты OSGi разрабатываются с помощью мастера New Plug-in Project, как показано ниже:
С помощью мастера создайте два проекта ( us.elron.osgi.random и us.elron.osgi.user ), выполнив необходимые шаги и назовите ваши пакеты и Activators ( RandomActivator , UserActivator ), как показано ниже. Конечный результат проекта также должен быть таким:
Определения служб, реализации и определения MANIFEST пакета, генерирующего случайные числа ( us.elron.osgi.random ), приведены ниже.
Интерфейс (IRandomGenerator):
1
2
3
4
5
6
7
8
9
|
package us.elron.osgi.random; public interface IRandomGenerator { int generate (); int generate( int upperBound); } |
Сервис (RandomGenerator):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package us.elron.osgi.random.generator; import java.util.Random; import us.elron.osgi.random.IRandomGenerator; public class RandomGenerator implements IRandomGenerator { private final Random random; public RandomGenerator () { this .random = new Random(); } @ Override public int generate () { return this .random.nextInt(); } @ Override public int generate ( final int upperBound) { return this .random.nextInt (upperBound); } } |
Активатор (RandomActivator) :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
package us.elron.osgi.random; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import us.elron.osgi.random.generator.RandomGenerator; public class RandomActivator implements BundleActivator { public void start( final BundleContext context) throws Exception { System.out.println( "[Random] Let's 'Random'!" ); RandomGenerator randomGenerator = new RandomGenerator(); context.registerService(IRandomGenerator. class .getName (), randomGenerator, null ); System.out.println( "[Random] Random services were registered." ); } public void stop( final BundleContext context) throws Exception { System.out.println( "[Random] Bundle is being stopped !" ); } } |
Описание компонента MANIFEST.MF будет следующим. Пакет должен по крайней мере экспортировать пакеты, которые имеют свои сервисные интерфейсы, чтобы использовать их в других пакетах. Поскольку слабая связь является одной из наиболее важных целей систем SOA и OSGi, из любого пакета следует экспортировать только минимально необходимый набор классов.
01
02
03
04
05
06
07
08
09
10
11
|
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Random Bundle-SymbolicName: us.elron.osgi.random Bundle-Version: 1.0.0.qualifier Bundle-Activator: us.elron.osgi.random.RandomActivator Bundle-Vendor: ELRON.US Require-Bundle: org.eclipse.core.runtime Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: us.elron.osgi.random |
Как можно видеть, сервис является реализацией интерфейса Java, зарегистрированного как сервис OSGi. Класс Activator — это точка доступа OSGi пакета. OSGi использует класс Activator пакета для управления его жизненным циклом. При этом OSGi отправляет реализацию пакета « org.osgi.framework.BundleContext » в комплект. Этот интерфейс позволяет связке взаимодействовать со слоем OSGi и, как видно из кода, выполнять такие операции, как регистрация и получение службы OSGi.
Теперь давайте посмотрим на классы пользовательских пакетов:
Это класс, который печатает случайные числа, сгенерированные службой генератора случайных чисел.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package us.elron.osgi.user; import us.elron.osgi.random.IRandomGenerator; public class RandomPrinter extends Thread { private final IRandomGenerator random; private volatile boolean run = true ; public RandomPrinter ( final IRandomGenerator random) { this .random = random; } @ Override public void run () { while ( this .run) { System.out.println ( "[User] new random number: " + this .random.generate ( 300 )); try { Thread.sleep ( 1000 ); } catch ( final InterruptedException e) { break ; } } System.out.println ( "[User] The process was terminated." ); } public void close () { this .run = false ; } } |
и это реализация Activator:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package us.elron.osgi.user; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import us.elron.osgi.random.IRandomGenerator; public class UserActivator implements BundleActivator { private RandomPrinter randomPrinter; public void start ( final BundleContext context) throws Exception { System.out.println ( "[User] Here we go .." ); ServiceReference randSrvRef = context.getServiceReference (IRandomGenerator. class .getName ()); IRandomGenerator randService = (IRandomGenerator) context.getService (randSrvRef); if (randService == null ) { throw new Exception ( "[User] Error! Random service could not be found!" ); } this .randomPrinter = new RandomPrinter(randService); this .randomPrinter.start(); } public void stop ( final BundleContext bundleContext) throws Exception { System.out.println ( "[User] finish .." ); this .randomPrinter.close (); } } |
MANIFEST.MF описание «пользовательского» пакета будет следующим. Мы должны определить зависимость с помощью пакета случайных генераторов «us.elron.osgi.random», в котором находится интерфейс произвольного сервиса. Зависимости могут быть определены на уровне пакета или пакета, однако, чтобы уменьшить зависимости между пакетами, лучше всего лучше использовать зависимость на уровне пакета.
01
02
03
04
05
06
07
08
09
10
11
|
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: User Bundle-SymbolicName: us.elron.osgi.user Bundle-Version: 1.0.0.qualifier Bundle-Activator: us.elron.osgi.user.UserActivator Bundle-Vendor: ELRON.US Require-Bundle: org.eclipse.core.runtime Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Import-Package: us.elron.osgi.random |
Чтобы запустить эти проекты в OSGi с использованием Eclipse, необходимо определить конфигурацию запуска, как показано ниже. На шаге « Запуск (или отладка ) конфигураций » в OSGi Framework необходимо создать новую конфигурацию (щелкнув правой кнопкой мыши) и выбрать новые комплекты в этой конфигурации. Чтобы предоставить необходимые зависимости для выбранных пакетов, мы можем использовать «Добавить необходимые пакеты». ». Таким образом, Eclipse разрешит иерархию зависимостей и добавит необходимые пакеты для выбранных. Мы также должны определить порядок запуска пакетов. Этот порядок должен быть определен в соответствии с зависимостями комплектов. Зависимые пакеты должны начинаться после пакетов, от которых они зависят. Итак, в нашем примере мы установим уровень «us.elron.osgi.random» на 1 , а « us.elron.osgi.user » установим на 2 .
Выполнение проекта с этой формой создает вывод, как показано ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
OSGi> [Random] Let 's ' Random'! [Random] Random services were registered. [User] Here we go .. [User] new random number: 38 [User] new random number: 250 [User] new random number: 94 [User] new random number: 150 [User] new random number: 215 [User] new random number: 124 [User] new random number: 195 [User] new random number: 260 [User] new random number: 276 [User] new random number: 129 |
OSGi Runtime предоставляет консольный интерфейс для взаимодействия с самим собой. При запуске окна приложения консоли мы видим сценарий «osgi>» , который говорит, что мы можем получить доступ к консоли. После упоминания о нескольких важных командах, которые вы можете выполнить в консоли, я оставлю вас наедине с консолью, чтобы вы могли узнать, что там можно сделать, начиная с команды «help» .
Команда «ss» показывает все компоненты, зарегистрированные в OSGi, с их значениями id , состояния и имени пакета вместе с версией версии . Значение id указывает уникальный идентификатор, данный OSGi каждому пакету. Это число остается неизменным при выполнении JVM, даже если пакет удален и установлен снова (одна вещь, которую нужно обнаружить), но его можно изменить в новом исполнении. Значения состояния указывают на состояние пакета (подробно и объяснено в таблице выше), а значения name и version указывают на то, что их имена вызывают у нас. Для текущей системы вывод команды «ss» выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
OSGi> ss Framework is launched. id State Bundle 0 ACTIVE org.eclipse.osgi_3.6.0.v20100517 Fragments = 4 2 ACTIVE org.eclipse.core.jobs_3.5.0.v20100515 3 ACTIVE javax.servlet_2.5.0.v200910301333 Resolved javax.transaction_1.1.1.v201006150915 4 Master = 0 5 ACTIVE org.eclipse.core.runtime_3.6.0.v20100505 6 ACTIVE org.eclipse.equinox.preferences_3.3.0.v20100503 7 ACTIVE org.eclipse.osgi.services_3.2.100.v20100503 8 ACTIVE org.eclipse.core.runtime.compatibility.auth_3.2.200.v20100517 9 ACTIVE us.elron.osgi.random_1.0.0.qualifier Resolved org.eclipse.core.runtime.compatibility.registry_3.3.0.v20100520 10 Master = 11 11 ACTIVE org.eclipse.equinox.registry_3.5.0.v20100503 Fragments = 10 12 ACTIVE org.eclipse.equinox.app_1.3.0.v20100512 13 ACTIVE org.eclipse.equinox.common_3.6.0.v20100503 14 ACTIVE org.eclipse.core.contenttype_3.4.100.v20100505 14-1235 15 ACTIVE us.elron.osgi.user_1.0.0.qualifier OSGi> |
Давайте предположим, что мы хотим отключить наш пользовательский пакет. В этом случае нам нужно выполнить команду «stop» с идентификатором пакета, который мы хотим остановить (в данном случае 15).
1
2
3
4
5
|
[User] a new random number is: 48 [User] a new random number is: 49 OSGi> stop 15 [User] finish .. [User] The process was terminated. |
Когда мы снова посмотрим на вывод команды «ss» ,
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
Framework is launched. id State Bundle 0 ACTIVE org.eclipse.osgi_3.6.0.v20100517 Fragments = 4 2 ACTIVE org.eclipse.core.jobs_3.5.0.v20100515 3 ACTIVE javax.servlet_2.5.0.v200910301333 Resolved javax.transaction_1.1.1.v201006150915 4 Master = 0 5 ACTIVE org.eclipse.core.runtime_3.6.0.v20100505 6 ACTIVE org.eclipse.equinox.preferences_3.3.0.v20100503 7 ACTIVE org.eclipse.osgi.services_3.2.100.v20100503 8 ACTIVE org.eclipse.core.runtime.compatibility.auth_3.2.200.v20100517 9 ACTIVE us.elron.osgi.random_1.0.0.qualifier Resolved org.eclipse.core.runtime.compatibility.registry_3.3.0.v20100520 10 Master = 11 11 ACTIVE org.eclipse.equinox.registry_3.5.0.v20100503 Fragments = 10 12 ACTIVE org.eclipse.equinox.app_1.3.0.v20100512 13 ACTIVE org.eclipse.equinox.common_3.6.0.v20100503 14 ACTIVE org.eclipse.core.contenttype_3.4.100.v20100505-1235 15 RESOLVED us.elron.osgi.user_1.0.0.qualifier |
мы видим, что состояние пользовательского пакета с идентификатором 15 установлено (см. раздел «Жизненный цикл»). Аналогично, мы можем выполнить команду запуска (запуск 15), чтобы запустить пакет и наблюдать, как процесс начал работать снова, или выполнить команду « s », чтобы просмотреть все службы, зарегистрированные в OSGi, или использовать команду удаления для удаления пакета из OSGi . Вы можете обнаружить!
В этой статье я попытался просто объяснить, что такое OSGi , как он работает и что с ним можно сделать. Надеюсь, тебе понравится. Вы можете скачать источники здесь .
Не стесняйтесь комментировать или связаться через elron [at] elron.us. Я буду рад услышать от вас.
Ссылка: OSGi: Введение от нашего партнера JCG Элрона в блоге Ender Ayd? N Orak .
Статьи по Теме :