Inleiding tot OSGi

1. Inleiding

Verschillende missiekritische Java-applicaties en middleware-applicaties stellen harde technologische vereisten.

Sommige moeten hot deploy ondersteunen om de actieve services niet te verstoren - en andere moeten met verschillende versies van hetzelfde pakket kunnen werken om externe legacy-systemen te ondersteunen.

De OSGi platforms vormen een haalbare oplossing om aan dit soort vereisten te voldoen.

De Open Service Gateway Initiative is een specificatie die een op Java gebaseerd componentensysteem definieert. Het wordt momenteel beheerd door de OSGi Alliantie, en de eerste versie dateert uit 1999.

Sindsdien is het een uitstekende standaard gebleken voor componentensystemen en wordt het tegenwoordig veel gebruikt. De Eclipse IDEis bijvoorbeeld een OSGi-gebaseerde applicatie.

In dit artikel zullen we enkele basisfuncties van OSGi gebruikmakend van de implementatie die wordt geboden door Apache.

2. OSGi Basics

In OSGi wordt een enkele component een bundel genoemd.

Logisch, een bundel is een stuk functionaliteit met een onafhankelijke levenscyclus - wat betekent dat het onafhankelijk kan worden gestart, gestopt en verwijderd.

Technisch gezien is een bundel slechts een jar-bestand met een MANIFEST.MF bestand met enkele OSGi-specifieke headers.

De OSGi platform biedt een manier om meldingen te ontvangen over bundels die beschikbaar komen of wanneer ze van het platform worden verwijderd. Hierdoor kan een goed ontworpen client blijven werken, misschien met verminderde functionaliteit, zelfs wanneer een service waarvan hij afhankelijk is, tijdelijk niet beschikbaar is.

Daarom moet een bundel expliciet aangeven tot welke pakketten het toegang moet hebben en de OSGi platform zal het alleen starten als de afhankelijkheden beschikbaar zijn in de bundel zelf of in andere bundels die al op het platform zijn geïnstalleerd.

3. Verkrijgen van de tools

We beginnen onze reis binnen OSGi door de nieuwste versie van Apache Karaf van deze link. Apache Karaf is een platform dat draait OSGi-gebaseerde applicaties; het is gebaseerd op de Apache‘S implementatie van OSGi specificatie genoemd Apache Felix.

Karaf biedt een aantal handige functies bovenop Felix dat zal ons helpen om vertrouwd te raken met OSGibijvoorbeeld een opdrachtregelinterface waarmee we met het platform kunnen communiceren.

Installeren Karaf, kunt u de installatie-instructies volgen uit de officiële documentatie.

4. Toegangspunt bundel

Om een ​​applicatie in een OSGi-omgeving uit te voeren, moeten we deze inpakken als een OSGi bundel en definieer het toegangspunt van de applicatie, en dat is niet gebruikelijk public static void main (String [] args) methode.

Dus laten we beginnen met het bouwen van een OSGi- gebaseerde "Hello World" applicatie.

We beginnen met het opzetten van een eenvoudige afhankelijkheid van de kern OSGi API:

 org.osgi org.osgi.core 6.0.0 voorzien 

De afhankelijkheid wordt verklaard als voorzien omdat het beschikbaar zal zijn in de OSGi runtime, en de bundel hoeft deze niet in te sluiten.

Laten we nu het simpele schrijven Hallo Wereld klasse:

openbare klasse HelloWorld implementeert BundleActivator {public void start (BundleContext ctx) {System.out.println ("Hallo wereld."); } public void stop (BundleContext bundleContext) {System.out.println ("Tot ziens wereld."); }}

BundleActivator is een interface die wordt geboden door OSGi dat moet worden geïmplementeerd door klassen die toegangspunten zijn voor een bundel.

De begin() methode wordt aangeroepen door de OSGi platform wanneer de bundel met deze klasse wordt gestart. Aan de andere kant hou op() wordt aangeroepen voordat de bundel wordt gestopt.

Houd er rekening mee dat elke bundel er maximaal één kan bevatten BundleActivator. De BundleContext object dat aan beide methoden wordt verstrekt, maakt interactie mogelijk met de OSGi looptijd. We komen er binnenkort op terug.

5. Bouwen aan een bundel

Laten we het pom.xml en maak er een echte OSGi-bundel van.

Allereerst moeten we expliciet aangeven dat we een bundel gaan bouwen, geen pot:

bundel

Vervolgens maken we gebruik van de maven-bundel-plugin, met dank aan de Apache Felix community, om het Hallo Wereld klasse als een OSGi bundel:

 org.apache.felix maven-bundle-plugin 3.3.0 true $ {pom.groupId}. $ {pom.artifactId} $ {pom.name} $ {pom.version} com.baeldung.osgi.sample.activator.HelloWorld com.baeldung.osgi.sample.activator 

In de instructiesectie specificeren we de waarden van de OSGi headers die we willen opnemen in het MANIFEST-bestand van de bundel.

Bundel-Activator is de volledig gekwalificeerde naam van het BundleActivator implementatie die zal worden gebruikt om de bundel te starten en te stoppen, en het verwijst naar de klasse die we zojuist hebben geschreven.

Privé-pakket is geen OSGi-header, maar wordt gebruikt om de plug-in te vertellen het pakket in de bundel op te nemen, maar het niet beschikbaar te maken voor andere. We kunnen nu de bundel bouwen met het gebruikelijke commando mvn schone installatie.

6. De bundel installeren en gebruiken

Laten we beginnen Karaf door het commando uit te voeren:

/ bin / karaf start

waar is de map waar Karaf is geinstalleerd. Wanneer de prompt van het Karaf console verschijnt, kunnen we de volgende opdracht uitvoeren om de bundel te installeren:

> bundel: installeer mvn: com.baeldung / osgi-intro-sample-activator / 1.0-SNAPSHOT Bundel-ID: 63

Dit geeft Karaf de opdracht om de bundel te laden vanuit de lokale Maven-repository.

In ruil daarvoor drukt Karaf de numerieke ID af die aan de bundel is toegewezen en die afhankelijk is van het aantal reeds geïnstalleerde bundels en kan variëren. De bundel is nu zojuist geïnstalleerd, we kunnen hem nu starten met het volgende commando:

> bundel: start 63 Hello World

"Hello World" verschijnt onmiddellijk zodra de bundel wordt gestart. We kunnen de bundel nu stoppen en verwijderen met:

> bundel: stop 63> bundel: verwijderen 63

"Goodbye World" verschijnt op de console, overeenkomstig de code in het hou op() methode.

7. Een OSGi-service

Laten we doorgaan met het schrijven van een eenvoudig OSGi service, een interface die een methode onthult om mensen te begroeten:

pakket com.baeldung.osgi.sample.service.definition; publieke interface Greeter {public String sayHiTo (String naam); }

Laten we er een implementatie van schrijven die een BundleActivator ook, zodat we de service kunnen instantiëren en op het platform kunnen registreren wanneer de bundel wordt gestart:

pakket com.baeldung.osgi.sample.service.implementation; openbare klasse GreeterImpl implementeert Greeter, BundleActivator {privé ServiceReference-referentie; private ServiceRegistration registratie; @Override public String sayHiTo (String naam) {return "Hallo" + naam; } @Override public void start (BundleContext context) genereert Uitzondering {System.out.println ("Registreerservice."); registration = context.registerService (Greeter.class, nieuwe GreeterImpl (), nieuwe Hashtable ()); reference = registration .getReference (); } @Override public void stop (BundleContext context) genereert Uitzondering {System.out.println ("Registreer service."); registration.unregister (); }}

Wij gebruiken de BundleContext als een manier om de OSGi platform om een ​​nieuw exemplaar van de service te registreren.

We moeten ook het type service en een kaart van de mogelijke configuratieparameters verstrekken, die in ons eenvoudige scenario niet nodig zijn. Laten we nu verder gaan met de configuratie van het maven-bundel-plugin:

 org.apache.felix maven-bundle-plugin true $ {project.groupId}. $ {project.artifactId} $ {project.artifactId} $ {project.version} com.baeldung.osgi.sample.service.implementation.GreeterImpl com .baeldung.osgi.sample.service.implementation com.baeldung.osgi.sample.service.definition 

Het is vermeldenswaard dat alleen de com.baeldung.osgi.sample.service.definition pakket is deze keer geëxporteerd via het Export-pakket koptekst.

Dankzij dit, OSGi staat andere bundels toe om alleen de methoden aan te roepen die in de service-interface zijn gespecificeerd. Pakket com.baeldung.osgi.sample.service.implementation is gemarkeerd als privé, dus geen enkele andere bundel heeft rechtstreeks toegang tot de leden van de implementatie.

8. Een OSGi-client

Laten we nu de klant schrijven. Het zoekt eenvoudig de service op bij het opstarten en roept deze op:

public class Client implementeert BundleActivator, ServiceListener {}

Laten we het BundleActivator start () methode:

privé BundleContext ctx; privé ServiceReference serviceReference; openbare ongeldige start (BundleContext ctx) {this.ctx = ctx; probeer {ctx.addServiceListener (this, "(objectclass =" + Greeter.class.getName () + ")"); } catch (InvalidSyntaxException ise) {ise.printStackTrace (); }}

De addServiceListener () methode stelt de client in staat om het platform te vragen om meldingen te verzenden over de service die voldoet aan de opgegeven uitdrukking.

De uitdrukking gebruikt een syntaxis die vergelijkbaar is met die van LDAP, en in ons geval vragen we om meldingen over een Greeter onderhoud.

Laten we verder gaan met de callback-methode:

openbare ongeldige serviceChanged (ServiceEvent serviceEvent) {int type = serviceEvent.getType (); switch (type) {case (ServiceEvent.REGITED): System.out.println ("Melding van geregistreerde service."); serviceReference = serviceEvent .getServiceReference (); Greeter-service = (Greeter) (ctx.getService (serviceReference)); System.out.println (service.sayHiTo ("John")); breken; case (ServiceEvent.UNREGISTERING): System.out.println ("Melding van service niet geregistreerd."); ctx.ungetService (serviceEvent.getServiceReference ()); breken; standaard: pauze; }}

Wanneer een wijziging met betrekking tot de Greeter service gebeurt, wordt de methode gemeld.

Wanneer de service op het platform is geregistreerd, krijgen we een verwijzing ernaar, slaan we deze lokaal op en gebruiken we deze om het serviceobject te verkrijgen en aan te roepen.

Wanneer de server later wordt afgemeld, gebruiken we de eerder opgeslagen referentie om deze te verwijderen, wat betekent dat we het platform vertellen dat we deze niet meer gaan gebruiken.

We hoeven nu alleen het hou op() methode:

openbare ongeldige stop (BundleContext bundleContext) {if (serviceReference! = null) {ctx.ungetService (serviceReference); }}

Ook hier verwijderen we de service om het geval te dekken waarin de klant wordt gestopt voordat de service wordt gestopt. Laten we een laatste blik werpen op de afhankelijkheden in het pom.xml:

 com.baeldung osgi-intro-sample-service 1.0-SNAPSHOT verstrekt org.osgi org.osgi.core 6.0.0 

9. Klant en service

Laten we nu de client- en servicebundels in Karaf installeren door het volgende te doen:

> mvn installeren: com.baeldung / osgi-intro-sample-service / 1.0-SNAPSHOT Bundel-ID: 64> mvn installeren: com.baeldung / osgi-intro-sample-client / 1.0-SNAPSHOT Bundel-ID: 65

Houd er altijd rekening mee dat de identificatienummers die aan elke bundel worden toegewezen, kunnen variëren.

Laten we nu de clientbundel starten:

> start 65

Daarom gebeurt er niets omdat de klant actief is en wacht op de service, waarmee we kunnen beginnen:

> start 64 Dienst registreren. Service geregistreerd. Hallo John

Wat er gebeurt, is dat zodra de BundleActivator van de service start, de service wordt geregistreerd op het platform. Dat meldt op zijn beurt de klant dat de service waarop hij wachtte, beschikbaar is.

De klant krijgt vervolgens een verwijzing naar de service en gebruikt deze om de implementatie aan te roepen die via de servicebundel wordt geleverd.

10. Conclusie

In dit artikel hebben we de essentiële functies van OSGi onderzocht met een duidelijk voorbeeld dat voldoende is om het potentieel van OSGi te begrijpen.

Concluderend, wanneer we moeten garanderen dat een enkele applicatie zonder enige slechte dienst moet worden bijgewerkt, kan OSGi een haalbare oplossing zijn.

De code voor dit bericht is te vinden op GitHub.