Статьи

OSGi Использование Maven с Equinox

Я изо всех сил пытался понять, что на самом деле означает OSGi . Он существует уже очень давно, но не многие знают об этом. Это было раскручено как очень сложная технология для понимания. Вот моя попытка сделать это простым для любого разработчика Java.

Короче говоря, OSGi — это группа спецификаций, которые обеспечивают модульную сборку программного обеспечения, созданного с использованием технологии Java. Он определяет создание и регистрацию (в контейнере с поддержкой OSGi ) компонентов — сервисов для взаимодействия внутри сети. Еще одним преимуществом OSGi является то, что все эти службы могут быть установлены / не установлены / запущены / остановлены во время выполнения (т. Е. Код может быть оперативно развернут во время выполнения). Подобно реализациям контейнеров сервлетов, таким как контейнеры Tomcat и EJB, которые можно найти на популярных серверах приложений J2EE, таких как WebSphere , JBoss , WebLogic , OSGi также имеет некоторые популярные реализации контейнеров, такие как Equinox (который является основой для Eclipse ), Apache Felix … и т. Д.

Сервисно-ориентированный подход является одной из сильных сторон OSGi, но я не должен забывать упомянуть еще одну, которая, на мой взгляд, очень важна, когда вам приходится иметь дело с приложением с множеством зависимостей. OSGi решает проблему «Jar Hell».
Пример. Предположим, вы используете две библиотеки, libX и libY, в вашем приложении. Также предположим, что у каждого из них есть зависимость в libZ, но с разными версиями. libX зависит от libZ 2.0, а libY зависит от libZ 1.0
Если libZ 2.0 несовместима с libZ 1.0, вы можете столкнуться с трудной проблемой, которую сможете решить, если использовать оба из них в одном приложении.
OSGi может справиться с такими проблемами. OSGi поддерживает директиву Import-Package , которая может использоваться для указания версии для любого пакета Java, используемого вашим приложением — сервис должен использовать. Загрузчик классов OSGi может найти правильный пакет / банку на основе этой информации.
В моем предыдущем примере, если бы библиотеки libX, libY и libZ были совместимы с OSGi, можно было бы без проблем загрузить их все в одну и ту же JVM:
libZ 1.0 будет использовать директиву Export-Package org.libz; версия = 1.0
libZ 2.0 будет использовать директиву Export-Package org.libz; версия = 2,0
libX будет использовать директиву Import-Package org.libz; версия = 2,0
libY будет использовать директиву Import-Package org.libz; версия = 1.0
OSGi также привносит более сильную концепцию модульности в Java-приложения. Только пакеты, экспортированные с использованием директивы Export-Package, могут использоваться вне пакета.

В этой статье я собираюсь объяснить OSGi с использованием контейнера Eclipse Equinox . Любой, у кого на компьютере установлена Eclipse IDE, также имеет контейнер OSGi в папке плагина Eclipse .

Имя файла jar контейнера OSGi выглядит как org.eclipse.osgi_ <версия> .jar

Вы можете запустить OSGi, как это

1
java -jar org.eclipse.osgi_3.5.2.R35x_v20100126.jar -console

Прикреплен пример скриншота того, как я запустил свой контейнер OSGi (аналогично запуску Tomcat )

Теперь, когда мы запустили контейнер OSGi , давайте создадим OSGi- приложение «HelloWorld» с использованием Maven . Структура проекта показана ниже:

Ниже приводится pom.xml для проекта. В pom.xml добавлено еще 2 профиля, чтобы создать еще 2 новых модуля ( MathService и MathServiceClient ), которые будут объяснены позже в этой статье.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.linkwithweb.osgi</groupId>
    <artifactId>HelloWorld</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>HelloWorld</name>
    <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>4.2.0</version>
        </dependency>
    </dependencies>
 
    <build>
        <finalName>HelloWorld-${version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.1</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
 
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
    <profiles>
        <profile>
            <id>MathService</id>
            <build>
                <finalName>MathService-${version}</finalName>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>2.3.1</version>
                        <configuration>
                            <source>1.5</source>
                            <target>1.5</target>
                        </configuration>
                    </plugin>
 
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <configuration>
 
                            <excludes>
                                <exclude>**/*.xml</exclude>
                                <exclude>**/*.bsh</exclude>
                                <exclude>**/*.properties</exclude>
                            </excludes>
                            <archive>
                                <manifestFile>src/main/resources/MathService/META-INF/MANIFEST.MF</manifestFile>
                            </archive>
                        </configuration>
                    </plugin>
 
                </plugins>
            </build>
        </profile>
        <profile>
            <id>MathServiceClient</id>
            <build>
                <finalName>MathServiceClient-${version}</finalName>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>2.3.1</version>
                        <configuration>
                            <source>1.5</source>
                            <target>1.5</target>
                        </configuration>
                    </plugin>
 
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <configuration>
 
                            <excludes>
                                <exclude>**/*.xml</exclude>
                                <exclude>**/*.bsh</exclude>
                                <exclude>**/*.properties</exclude>
                            </excludes>
                            <archive>
                                <manifestFile>src/main/resources/MathServiceClient/META-INF/MANIFEST.MF</manifestFile>
                            </archive>
                        </configuration>
                    </plugin>
 
                </plugins>
            </build>
        </profile>
    </profiles>
 
</project>

Если вы внимательно посмотрите на pom.xml, вы увидите, что есть 3 определения MANIFEST.MF, по одному для каждого отдельного пакета OSGi, который мы создаем. Скажем так, позвольте мне объяснить, что такое пакеты OSGi . Пакет OSGi, по сути, такой же, как и стандартный Java-файл «jar», с конкретной конфигурацией пакета, определенной в файле манифеста «jar». Все записи OSGi в файле манифеста jar считываются контейнером OSGi, чтобы активировать пакет. Разве это не круто? С OSGi мы избегаем изучения любых новых форматов метаданных, как с другими фреймворками!

Вот пример Manifest.MF, который я определил для пакета MathServiceClient

1
2
3
4
5
6
Manifest-Version: 1.0
Bundle-Name: MathServiceClient
Bundle-Activator: com.linkwithweb.osgi.service.client.MathServiceClientActivator
Bundle-SymbolicName: MathServiceClient
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework,com.linkwithweb.osgi.service

Как видите, все записи, кроме Manifest-Version, относятся к OSGi . Эти записи определяют, как активировать пакет, имя и версию пакета, все его зависимые библиотеки и какие точки расширения он предоставляет другим службам для использования … и т. Д.

Позвольте мне показать вам, как установить пакет «HelloWorld» в Equinox OSGi Container. Ниже приведены файл MANIFEST.MF и класс Activator для пакета «HelloWorld».

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package com.linkwithweb.osgi;
 
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
 
/**
 * @author Ashwin Kumar
 *
 */
public class HelloActivator implements BundleActivator {
    public void start(BundleContext context) {
        System.out.println("Hello World");
    }
 
    public void stop(BundleContext context) {
        System.out.println("Goodbye All");
    }
}
1
2
3
4
5
6
Manifest-Version: 1.0
Bundle-Name: HelloWorld
Bundle-Activator: com.linkwithweb.osgi.HelloActivator
Bundle-SymbolicName: HelloWorld
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework

Для сборки вашего пакета запустите «mvn clean package»

Он создаст HelloWorld-0.0.1-SNAPSHOT.jar в целевой папке вашего проекта Maven . Вот изображение, которое показывает, как установить и запустить наш пакет «HelloWorld» в Equinox

Как вы можете видеть, мы использовали команду install для установки пакета и команду start, используя идентификатор пакета, возвращаемый контейнером после установки пакета, для запуска пакета.

Теперь, что касается жизненного цикла комплекта, запуск комплекта инициирует вызов метода « start » класса Activator комплекта, тогда как остановка комплекта вызывает вызов метода « stop » класса Activator комплекта. Мы можем видеть результаты вышеупомянутого поведения в терминале контейнера, где сообщение «Hello World» отображается при запуске модуля!

Поздравляем, вы изучили основы OSGi и только что развернули свой первый пакет!

Разоблачение и использование услуг

Чтобы объяснить это, я реализую очень простой пример, где я опубликую сервис, который может добавить 2 номера.

Сначала нам нужно определить интерфейс для предоставления нашей «добавляемой» функциональности внешним пакетам (клиентам).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package com.linkwithweb.osgi.service;
 
/**
 * @author Ashwin Kumar
 *
 */
public interface MathService {
 
    /**
     * @param a
     * @param b
     * @return
     */
    public int add(int a, int b);
}

Теперь класс реализации

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
package com.linkwithweb.osgi.service;
 
/**
 * @author Ashwin Kumar
 *
 */
public class MathServiceImpl implements MathService {
 
    /* (non-Javadoc)
     * @see com.linkwithweb.osgi.service.MathService#add(int, int)
     */
    public int add(int a, int b) {
        // TODO Auto-generated method stub
        return a+b;
    }
 
}

Далее следует класс Activator, который регистрирует услугу «Добавление» в контейнер 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
32
package com.linkwithweb.osgi.service;
 
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
 
/**
 * @author Ashwin Kumar
 *
 */
public class MathServiceActivator implements BundleActivator {
    /*
     * (non-Javadoc)
     *
     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
     */
    public void start(BundleContext context) {
        MathService service = new MathServiceImpl();
        // Third parameter is a hashmap which allows to configure the service
        // Not required in this example
        context.registerService(MathService.class.getName(), service, null);
        System.out.println("Math Service Registered");
    }
 
    /*
     * (non-Javadoc)
     *
     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) {
        System.out.println("Goodbye From math service");
    }
}

Ниже приведен файл манифеста для «добавления» пакета услуг.

1
2
3
4
5
6
7
Manifest-Version: 1.0
Bundle-Name: MathService
Bundle-Activator: com.linkwithweb.osgi.service.MathServiceActivator
Bundle-SymbolicName: MathService
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework
Export-Package: com.linkwithweb.osgi.service

Если вы наблюдаете манифест выше, вы заметите, что мы экспортируем некоторые пакеты, чтобы они могли быть использованы позже. Также весь пакет, который будет необходим во время выполнения, должен быть определен здесь (используя директиву Import-Package ).

Как и в предыдущем разделе этой статьи, используйте следующую команду для создания файла JAR

пакет mvn -PMathService

Ниже вы можете увидеть команды для установки и запуска пакета OSGi .

Ниже приведена реализация потребителем услуги «добавление». Потребитель упакован в класс активатора пакета OSGi только для демонстрационных целей. Вы можете реализовать потребителя как отдельный сервис 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
32
33
34
35
36
37
package com.linkwithweb.osgi.service.client;
 
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
 
import com.linkwithweb.osgi.service.MathService;
 
/**
 * @author Ashwin Kumar
 *
 */
public class MathServiceClientActivator implements BundleActivator {
    MathService service;
    private BundleContext context;
 
    /*
     * (non-Javadoc)
     *
     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
     */
    public void start(BundleContext context) {
        this.context = context;
        // Register directly with the service
        ServiceReference reference = context
                .getServiceReference(MathService.class.getName());
        service = (MathService) context.getService(reference);
        System.out.println(service.add(1, 2));
    }   /*
     * (non-Javadoc)
     *
     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) {
        System.out.println(service.add(5, 6));
    }
}

Follwing — это файл манифеста для «добавления» пакета потребителя сервиса.

1
2
3
4
5
6
Manifest-Version: 1.0
Bundle-Name: MathServiceClient
Bundle-Activator: com.linkwithweb.osgi.service.client.MathServiceClientActivator
Bundle-SymbolicName: MathServiceClient
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework,com.linkwithweb.osgi.service

Чтобы создать, установить и запустить клиентский пакет «добавление», выполните следующие действия:

пакет mvn -PMathServiceClient

Вот и все! Надеюсь, вам понравилось!

Вы можете скачать исходный код этой статьи здесь

Ссылка: OSGI для начинающих, использующих Maven с Equinox (HowTo) от нашего партнера JCG Асвина в блоге Felicitas и Beatitudo .

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