OSGI ist nicht schwierig
Ich habe oft getroffen, dass OSGI schwierig ist. Und außerdem hatte er selbst einmal eine solche Meinung. Jahr 2009, um genau zu sein. Zu dieser Zeit haben wir Projekte mit Maven Tycho gesammelt und für Equinox bereitgestellt. Und es war wirklich schwieriger als das Entwickeln und Zusammenstellen von Projekten für JavaEE (in diesem Moment erschien gerade die Version von EJB 3, zu der wir gewechselt haben). Equinox war zum Beispiel viel weniger praktisch als Weblogic, und die Vorteile von OSGI waren mir damals nicht klar.
Aber dann, nach vielen Jahren, musste ich ein Projekt an einem neuen Arbeitsplatz beginnen, das auf der Basis von Apache Camel und Apache Karaf konzipiert wurde. Dies war nicht meine Idee, ich kannte Camel schon lange und beschloss, auch ohne Angebot über Karaf zu lesen. Ich habe es eines Abends gelesen und festgestellt, dass es hier einfach und fertig ist, fast die gleiche Lösung für einige Probleme eines typischen JavaEE, ähnlich wie ich es einmal mit Weblogic WLST, Jython und Maven Aether auf meinem Knie gemacht habe.
Nehmen wir also an, Sie möchten OSGI auf der Karaf-Plattform ausprobieren. Mit was fangen wir an?
Wenn Sie ein tieferes Verständnis wollen
Sie können natürlich mit dem Lesen der Dokumentation beginnen. Und mit Habré ist das möglich - hier gab es sehr gute Artikel, sagen wir vor
so langer Zeit. Aber im Allgemeinen erhielt Karaf bisher unverdient wenig Aufmerksamkeit. Es gab noch ein paar Bewertungen
dies oder
das . Es ist besser,
diese Erwähnung von Karaf zu überspringen. Wie sie sagen, lesen Sie keine sowjetischen Zeitungen für die Nacht ... denn sie werden Ihnen dort sagen, dass Karaf ein OSGI-Rahmen ist - also glauben Sie es nicht. OSGI-Frameworks sind Apache Felix oder Eclipse Equinox, auf deren Grundlage Karaf nur funktioniert. Sie können einen von ihnen auswählen.
Es sollte beachtet werden, dass wenn Jboss Fuse oder Apache ServiceMix erwähnt wird, es als "Karaf mit vorinstallierten Komponenten" gelesen werden sollte, d. H. in der Tat - das gleiche, nur vom Verkäufer gesammelt. Ich würde nicht empfehlen, in der Praxis damit zu beginnen, aber es ist durchaus möglich, beispielsweise Übersichtsartikel über ServiceMix zu lesen.
Zunächst werde ich hier ganz kurz herausfinden, was OSGI ist und wofür es verwendet werden kann.
Im Großen und Ganzen ist OSGI ein Tool zum Erstellen von Java-Anwendungen aus Modulen. Ein enges Analogon kann beispielsweise als JavaEE betrachtet werden, und in gewissem Maße können OSGI-Container JavaEE-Module (z. B. Webanwendungen in Form von War) ausführen, und andererseits enthalten viele JavaEE-Container OSGI als Mittel zur Implementierung von Modularität "für sich" ". Das heißt, JavaEE und OSGI ähneln der Kompatibilität und ergänzen sich erfolgreich.
Ein wichtiger Bestandteil jedes modularen Systems ist die Definition des Moduls selbst. Im Fall von OSGI wird das Modul als Bundle bezeichnet, und es ist ein JAR-Archiv, das allen Entwicklern mit einigen Ergänzungen bekannt ist (das heißt, es ist hier beispielsweise Krieg oder Ohr sehr ähnlich). In Analogie zu JavaEE können Bundles Dienste exportieren und importieren, bei denen es sich im Wesentlichen um Klassenmethoden handelt (dh ein Dienst ist eine Schnittstelle oder alle öffentlichen Methoden einer Klasse).
Die Bundle-Metadaten sind allen META-INF / MANIFEST.MF bekannt. Die Header des OSGI-Manifests überschneiden sich nicht mit den Headern für die JRE. Außerhalb des OSGI-Container-Bundles befindet sich ein reguläres JAR. Es ist wichtig, dass es unter den Metadaten immer Folgendes gibt:
Bundle-SymbolicName: com.example.myosgi Bundle-Version: 1.0.0
Dies sind die „Koordinaten“ des Bundles, und die Tatsache, dass zwei oder mehr gleichzeitig installierte und funktionierende Versionen desselben Bundles in einem Container installiert werden können, ist wichtig.
Ähnlich wie bei JavaEE haben Bundles einen Lebenszyklus, der folgendermaßen aussieht:

Neben Diensten können Bundles auch Pakete importieren und exportieren (Pakete im üblichen Sinne des Begriffs für Java). Exportierte Pakete werden im Bundle definiert und anderen Komponenten zur Verfügung gestellt, wenn das Bundle auf dem System installiert wird. Die importierten werden irgendwo von außen definiert, müssen von jemandem exportiert und vom Container für das Bundle bereitgestellt werden, bevor es funktionieren kann.
Paketimporte können als optional deklariert werden, ebenso Serviceimporte. Es ist sehr wichtig, dass Import und Export einen Hinweis auf die Version (oder den Versionsbereich) enthalten.
Unterschiede zu JavaEE
Gut, dass sie sich ähneln - wir haben verstanden. Und wie unterscheiden sie sich?
Meiner Meinung nach besteht der Hauptunterschied darin, dass OSGI uns viel mehr Flexibilität bietet. Sobald sich das Bundle im Zustand STARTED befindet, sind die Möglichkeiten nur durch Ihre Vorstellungskraft begrenzt. Angenommen, Sie können problemlos Threads (ja, ja, ich kenne ManagedExecutorService), Verbindungspools zu Datenbanken usw. erstellen. Ein Container übernimmt nicht im gleichen Umfang die Kontrolle über alle Ressourcen wie JavaEE.
Sie können dabei neue Services exportieren. Versuchen Sie beispielsweise in JavaEE dynamisch ein neues Servlet zu erstellen? Und hier ist es durchaus möglich, dass der auf der Grundlage des Stegs erstellte Karaf-Servlet-Container sofort von Ihrem erstellten Servlet erkannt wird und den Kunden unter einer bestimmten URL zur Verfügung steht.
Dies ist zwar eine leichte Vereinfachung, aber wenn die JavaEE-Anwendung in ihrer klassischen Form hauptsächlich aus Komponenten besteht:
- passiv, wartet auf einen Anruf vom Client
- statisch definiert, dh zum Zeitpunkt der Bereitstellung der Anwendung.
Andererseits kann eine OSGI-basierte Anwendung Folgendes enthalten:
- aktive und passive geplante Komponenten, Durchführen von Umfragen, Abhören eines Sockets usw.
- Services können dynamisch definiert und veröffentlicht werden
- Sie können Framework-Ereignisse abonnieren, z. B. die Registrierung von Diensten, Bundles usw. abhören, Links zu anderen Bundles und Diensten erhalten und vieles mehr.
Ja, unter JavaEE ist vieles davon teilweise auch möglich (z. B. über JNDI), aber im Fall von OSGI wird dies in der Praxis einfacher. Obwohl es hier wahrscheinlich noch ein paar Risiken gibt.
Unterschiede zwischen Karaf und reinem OSGI
Neben dem Karaf-Framework gibt es viele nützliche Dinge. Im Wesentlichen ist Karaf ein Tool zur bequemen Verwaltung des OSGI-Frameworks - Installation von Bundles (einschließlich Gruppen), Konfiguration, Überwachung, Beschreibung des Vorbilds und Gewährleistung der Sicherheit und dergleichen.
Und lass uns schon üben?
Dann fangen wir gleich mit der Installation an. Hier gibt es nicht viel zu schreiben - gehen Sie zu karaf.apache.org, laden Sie das Distributionspaket herunter und entpacken Sie es. Karaf-Versionen unterscheiden sich in der Unterstützung verschiedener OSGI-Spezifikationen (4, 5 oder 6) und Java-Versionen. Ich empfehle die 2.x-Familie nicht, aber hier sind 3 (wenn Sie Java 8 haben, wie meine), und 4 können verwendet werden, obwohl heute nur die 4.x-Familie entwickelt wird (aktuelle Version 4.2.2, sie unterstützt OSGI 6) und Java bis zu 10).
Karaf funktioniert unter Windows und Linux einwandfrei. Alles, was Sie zum Erstellen eines Dienstes und zum Autorun benötigen, ist verfügbar. Die Unterstützung für MacOS und viele andere Unix-Typen wird ebenfalls deklariert.
Normalerweise können Sie Karaf sofort starten, wenn Sie im Internet sind. Wenn nicht, lohnt es sich normalerweise, die Konfigurationsdatei zu reparieren und anzugeben, wo Sie Maven-Repository (s) haben. Normalerweise wird es ein Corporate Nexus sein oder Artifactory sagen, wer was mag. Die Karaf-Konfiguration befindet sich im Ordner etc der Distribution. Die Namen der Konfigurationsdateien sind nicht sehr offensichtlich, aber in diesem Fall benötigen Sie die Datei org.ops4j.pax.url.mvn.cfg. Das Format dieser Datei ist Java-Eigenschaften.
Sie können die Repositorys sowohl in der Konfigurationsdatei selbst angeben, die Liste der URLs in den Einstellungen auflisten als auch einfach anzeigen, wo sich Ihre settings.xml befindet. Dort nimmt der Karaf den Standort Ihres Proxys ein, der normalerweise im Intranet bekannt sein muss.
Kafar benötigt mehrere Ports: HTTP, HTTPS (wenn das Web standardmäßig nicht konfiguriert ist), SSH, RMI, JMX. Wenn sie mit Ihnen beschäftigt sind oder Sie mehrere Kopien auf demselben Host ausführen möchten, müssen Sie diese ebenfalls ändern. Es gibt ungefähr fünf dieser Ports.
Ports wie jmx und rmi - hier: org.apache.karaf.management.cfg, ssh - org.apache.karaf.shell.cfg, um die http / https-Ports zu ändern, müssen Sie die Datei etc / erstellen (höchstwahrscheinlich nicht) org.ops4j.pax.web.cfg und schreiben Sie den Wert org.osgi.service.http.port = port, den Sie benötigen.
Dann können Sie es definitiv starten, und in der Regel wird alles beginnen. Für den industriellen Einsatz müssen Sie natürlich Änderungen an der Datei bin / setenv oder bin / setenv.bat vornehmen, um beispielsweise die erforderliche Speichermenge zuzuweisen. Zunächst ist dies jedoch nicht erforderlich.
Sie können Karaf sofort mit der Konsole oder dem Befehl karaf starten oder im Hintergrund mit dem Befehl start server ausführen und dann über SSH eine Verbindung herstellen. Dies ist ein Standard-SSH mit Unterstützung für SCP und SFTP. Sie können Befehle ausführen und Dateien hin und her kopieren. Es ist möglich, eine Verbindung mit einem beliebigen Client herzustellen. Mein Lieblingswerkzeug ist beispielsweise Far NetBox. Die Anmeldung erfolgt über Login und Passwort sowie über Schlüssel. In Innereien jsch, mit allem, was es impliziert.
Ich empfehle, sofort ein zusätzliches Konsolenfenster zu haben, um die Protokolle in data / log / karaf.log anzuzeigen (und andere Dateien sind normalerweise vorhanden, obwohl dies anpassbar ist). Protokolle sind nützlich für Sie, von Kurznachrichten in der Konsole ist nicht alles klar.
Ich würde empfehlen, das Web sofort und die Hawtio-Webkonsole zu installieren. Diese beiden Dinge erleichtern Ihnen die Navigation im Container und die Steuerung des Prozesses von dort aus (als Bonus erhalten Sie Jolokia und die Möglichkeit, über http zu überwachen). Die Installation von hawtio erfolgt über zwei Befehle von der Karaf-Konsole (
wie hier beschrieben ). Leider wird die Version von Karaf 3.x heute nicht mehr unterstützt (Sie müssen nach älteren Versionen von Hawtio suchen).
Standardmäßig ist https nicht sofort verfügbar. Dazu müssen Sie einige Anstrengungen unternehmen, z. B. das Generieren von Zertifikaten usw. Die Implementierung basiert auf einem Steg, sodass alle diese Bemühungen größtenteils auf die gleiche Weise ausgeführt werden.
OK, es fing an, was kommt als nächstes?

Was hast du eigentlich erwartet? Ich sagte, es wird ssh sein. Tab funktioniert, wenn das so ist.
Es ist Zeit, eine Anwendung zu installieren. Eine Anwendung für OSGI ist entweder ein Bundle oder besteht aus mehreren Bundles. Karaf kann Anwendungen in verschiedenen Formaten bereitstellen:
- Ein Glasbündel mit oder ohne OSGI-Manifest
- XML mit Spring DM oder Blueprint
- XML mit der sogenannten Funktion, einer Sammlung von Bundles, anderen Funktionen und Ressourcen (Konfigurationsdateien)
- .kar-Archiv mit mehreren Funktionen und einem Maven-Repository mit Abhängigkeiten
- JavaEE-Anwendungen (unter bestimmten Bedingungen), z. B. .war
Es gibt verschiedene Möglichkeiten, dies zu tun:
- Legen Sie die Anwendung im Bereitstellungsordner ab
- Installieren Sie von der Konsole mit dem Befehl install
- Installieren Sie die Funktion mit dem Befehl über die Funktion: Konsole installieren
- kar: installieren
Im Allgemeinen ist dies ziemlich ähnlich wie ein typischer JavaEE-Container, aber es ist etwas praktischer (ich würde sagen, es ist viel praktischer).
Einfaches Glas
Am einfachsten ist es, ein normales Glas zu installieren. Wenn Sie es im Maven-Repository haben, reicht der Befehl aus, um Folgendes zu installieren:
install mvn:groupId/artifactId/version
Gleichzeitig erkennt Karaf, dass er ein normales Glas vor sich hat, und verarbeitet es, indem er im laufenden Betrieb eine Bündelverpackung erstellt, die sogenannte Wrapper, der ein Standardmanifest generiert, mit Paketimporten und -exporten.
Der Sinn, nur ein Glas zu installieren, ist normalerweise nicht groß, da dieses Bundle passiv ist - es exportiert nur Klassen, die anderen Bundles zur Verfügung stehen.
Diese Methode wird verwendet, um Komponenten wie Apache Commons Lang zu installieren, zum Beispiel:
install mvn:org.apache.commons.lang3/commons-lang/3.8.1
Aber es hat nicht funktioniert :) Hier sind die richtigen Koordinaten:
install mvn:org.apache.commons/commons-lang3/3.8.1
Mal sehen, was passiert ist: list -u zeigt uns die Bundles und ihre Quellen:
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
Wie Sie sehen, ist es durchaus möglich, zwei Versionen einer Komponente zu installieren. Speicherort aktualisieren - Hier haben wir das Bundle erhalten und können es bei Bedarf aktualisieren.
Jar und Spring Kontext
Wenn sich in Ihrem Glas ein Frühlingskontext befindet, werden die Dinge interessanter. Karaf Deployer sucht automatisch nach XML-Kontexten im Ordner META-INF / spring und erstellt sie, wenn alle vom Bundle benötigten externen Bundles erfolgreich gefunden wurden.
Somit werden alle Dienste, die sich innerhalb der Kontexte befanden, bereits gestartet. Wenn Sie dort beispielsweise Camel Spring hatten, beginnen auch die Kamelrouten. Dies bedeutet, dass Sie einen REST-Dienst oder einen Dienst, der einen TCP-Port überwacht, bereits starten können. Das Starten mehrerer Dienste, die an einem Port lauschen, funktioniert natürlich nicht so.
Nur Spring XML-Kontext
Wenn Sie beispielsweise JDBC DataSources-Definitionen in Spring Context hatten, können Sie diese separat in Karaf installieren. Das heißt, Nehmen Sie eine XML-Datei, die nur eine DataSource in Form von <Bean> oder einem anderen Satz von Komponenten enthält, und legen Sie sie im Bereitstellungsordner ab. Der Kontext wird auf standardmäßige Weise gestartet. Das einzige Problem ist, dass auf diese Weise erstellte DataSources für andere Bundles nicht sichtbar sind. Sie müssen als Dienste nach OSGI exportiert werden. Darüber - etwas später.
Frühling dm
Was ist der Unterschied zwischen Spring DM (OSGI-fähige Version) und dem klassischen Spring? Im klassischen Fall werden also alle Beans im Kontext in der Initialisierungsphase des Kontexts erstellt. Neue können nicht erscheinen, alte gehen nirgendwo hin. Bei OSGI können neue Bundles installiert und alte Bundles entfernt werden. Die Umgebung wird dynamischer, Sie müssen irgendwie reagieren.
Die Antwortmethode heißt Dienste. Ein Dienst ist normalerweise eine bestimmte Schnittstelle mit eigenen Methoden, die von einem Bundle veröffentlicht wird. Ein Dienst verfügt über Metadaten, mit denen er gesucht und von einem anderen Dienst unterschieden werden kann, der eine ähnliche Schnittstelle implementiert (offensichtlich von einer anderen DataSource). Metadaten sind einfache Eigenschaften von Schlüsselwerten.
Da Dienste angezeigt und ausgeblendet werden können, können diejenigen, die sie benötigen, entweder beim Start Dienste abonnieren oder Ereignisse anhören, um Informationen zu ihrem Auftreten oder Verschwinden zu erhalten. Auf der Spring DM-Ebene wird dies in XML als zwei Elemente implementiert: Service und Referenz, deren grundlegender Zweck recht einfach ist: Veröffentlichen Sie die vorhandene Bean aus dem Kontext als Service und abonnieren Sie einen externen Service, indem Sie sie im aktuellen Spring-Kontext veröffentlichen.
Dementsprechend findet der Container beim Initialisieren eines solchen Bundles die externen Dienste, die er dafür benötigt, und veröffentlicht die darin implementierten Bundles, sodass sie von außen zugänglich sind. Ein Bundle wird erst gestartet, nachdem die Service-Links aufgelöst wurden.
Tatsächlich ist alles etwas komplizierter, da das Bundle eine Liste ähnlicher Dienste verwenden und die Liste sofort abonnieren kann. Das heißt, Ein Dienst hat im Allgemeinen eine Eigenschaft wie Kardinalität, die den Wert 0..N annimmt. In diesem Fall beschreibt das Abonnement, in dem 0..1 angegeben ist, einen optionalen Dienst. In diesem Fall wird das Bundle erfolgreich gestartet, auch wenn kein solcher Dienst im System vorhanden ist (und anstelle eines Links dazu wird ein Stub angezeigt).
Ich stelle fest, dass ein Dienst nur eine beliebige Schnittstelle ist (oder Sie können nur Klassen veröffentlichen), sodass Sie java.util.Map mit Daten als Dienst gut veröffentlichen können.
Mit dem Dienst können Sie unter anderem Metadaten angeben, und mit der Referenz können Sie anhand dieser Metadaten nach einem Dienst suchen.
Blaupause
Blueprint ist die neuere Spring DM-Inkarnation, die etwas einfacher ist. Wenn Sie im Frühjahr benutzerdefinierte XML-Elemente haben, sind diese nicht als unnötig vorhanden. Manchmal verursacht dies immer noch Unannehmlichkeiten, aber ehrlich gesagt - selten. Wenn Sie kein Projekt aus Spring migrieren, können Sie sofort mit Blueprint beginnen.
Das Wesentliche hier ist dasselbe - es ist XML, das die Komponenten beschreibt, aus denen der Bundle-Kontext zusammengestellt wird. Für diejenigen, die den Frühling kennen, gibt es überhaupt nichts Unbekanntes.
Hier ist ein Beispiel, wie eine DataSource beschrieben und als Service exportiert wird:
<?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>
Nun, wir haben diese Datei im Bereitstellungsordner bereitgestellt und uns die Ergebnisse des Befehls list angesehen. Sie sahen, dass das Bundle nicht gestartet wurde - im Status Indtalled. Wir versuchen zu starten und erhalten eine Fehlermeldung.
Jetzt in der Liste der Bundles im Status Fehlgeschlagen. Was ist los? Offensichtlich benötigt er auch Abhängigkeiten, in diesem Fall ein Jar mit Oracle JDBC-Klassen, genauer gesagt das Paket oracle.jdbc.pool.
Wir finden das erforderliche JAR im Repository oder laden es von der Oracle-Site herunter und installieren es wie zuvor beschrieben. Unsere DataSource hat begonnen.
Wie benutzt man das alles? Der Service-Link wird in der Blueprint-Referenz aufgerufen (irgendwo im Kontext eines anderen Bundles):
<reference id="dataSource" interface="javax.sql.DataSource"/>
Dann wird diese Bohne wie üblich zu einer Abhängigkeit für andere Bohnen (im Beispiel camel-sql):
<bean id="sql" class="org.apache.camel.component.sql.SqlComponent"> <property name="dataSource" ref="dataSource"/> </bean>
Glas und Aktivator
Die kanonische Methode zum Initialisieren von Bundles besteht darin, eine Klasse zu verwenden, die die Activator-Schnittstelle implementiert. Dies ist eine typische Lebenszyklusschnittstelle, die Start- und Stoppmethoden enthält, die den
Kontext übergeben . In ihnen startet das Bundle normalerweise seine Threads, beginnt bei Bedarf mit dem Abhören von Ports, abonniert externe Dienste mithilfe der OSGI-API usw. Dies ist vielleicht der komplexeste, grundlegendste und flexibelste Weg. Seit drei Jahren habe ich es nie gebraucht.
Einstellungen und Konfiguration
Es ist klar, dass eine solche Konfiguration der DataSource, wie im Beispiel gezeigt, nur wenige Personen benötigen. Login, Passwort und mehr, alles ist in XML fest codiert. Es ist notwendig, diese Parameter herauszunehmen.
<property name="url" value="${oracle.ds.url}"/> <property name="user" value="${oracle.ds.user}"/> <property name="password" value="${oracle.ds.password}"/>
Die Lösung ist recht einfach und ähnelt der im klassischen Frühling verwendeten: An einem bestimmten Punkt im Kontextlebenszyklus werden Eigenschaftswerte aus verschiedenen Quellen ersetzt.
Damit beenden wir den ersten Teil. Wenn Interesse an diesem Thema besteht, wird es fortgesetzt. Wir werden überlegen, wie Anwendungen aus Bundles zusammengestellt, Systeme auf dieser Plattform konfiguriert, überwacht und automatisch bereitgestellt werden.