Статьи

OSGi: Введение

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

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 .

Статьи по Теме :