Programmering

Hvad er OSGi? En anden tilgang til Java-modularitet

OSGi letter oprettelse og styring af modulære Java-komponenter (kaldet bundter), der kan indsættes i en container. Som udvikler bruger du OSGi-specifikationen og værktøjerne til at oprette et eller flere bundter. OSGi definerer livscyklussen for disse bundter. Det er også vært for dem og understøtter deres interaktioner i en container. Du kan tænke på en OSGi-container som omtrent analog med en JVM med yderligere beføjelser. Tænk ligeledes på bundter som Java-applikationer med unikke evner. Bundter kører inde i OSGi-containeren som klient- og serverkomponenter.

OSGi-alliancen

OSGi startede i 1999, og i modsætning til mange andre specifikationer styres standarden ikke af Oracle, Java Community Process eller Eclipse Foundation. I stedet styres det af OSGi-alliancen.

Hvordan OSGi er anderledes

OSGis filosofi adskiller sig fra andre Java-baserede rammer, især Spring. I OSGi kan der findes flere applikationer i samme container: OSGi bundt runtime-miljø. Beholderen sikrer, at hver komponent er tilstrækkeligt isoleret og også har adgang til de afhængigheder, den kræver. OSGi kan understøtte afhængighedsinjektion, som er standardiseret af Aries Blueprint-projektet. Ud over at levere OSGis inversion af kontrolcontainer (IoC) beholder Aries standard Java-rammer som Java Persistence API (JPA).

I OSGi kan bundter udsætte tjenester, som andre bundter bruger. Et bundt kan også erklære en version og kan definere, hvilke andre bundter det afhænger af. Runtiden indlæser automatisk alle dens bundter i rækkefølge efter afhængighed. I OSGi kan flere versioner af den samme pakke eksistere side om side, hvis det kræves af bundtafhængigheder.

OSGi i formørkelse IDE og equinox

OSGi har eksisteret i en eller anden form i et par årtier. Det bruges til mange kendte applikationer, fra indlejrede mobile enheder til applikationsservere og IDE'er.

Den populære Eclipse IDE er bygget oven på OSGi. Eclipse's implementering af OSGi-containeren kaldes Equinox. Det er et godt eksempel til forståelse af OSGi. At være baseret på OSGi betyder, at Equinox er en modulær platform. Det er vært for en række tjenester, som udviklere kan tilføje efter eget valg. Hver af disse tilbyder en kapacitet, som en udvikler muligvis har brug for i deres IDE. Du kan muligvis tilføje redaktører til Java og JavaScript, en app-server og et databasestik. Hver af disse implementeres som et OSGi-bundt, der føjes til containeren og kan interagere med andre tjenester i containeren.

For nylig har der været en interesse i at bruge OSGi til Internet of Things (IoT). OSGi er en naturlig pasform til denne type udvikling, som har en række softwarekomponenter, der kører side om side på enheder uden nødvendigvis at kende til hinanden. En OSGi-container giver en enkel og standardiseret måde at være vært for disse dynamiske softwarekomponenter på.

Brug af OSGi i et Java-projekt: Knoplerfish OSGi

Vi arbejder gennem et eksempel på en applikation, der gør OSGi-koncepter mere konkrete. Vores eksempel er baseret på Knoplerfish OSGi-runtime, som bruges i mange produktionsinstallationer. Knoplerfish inkluderer en GUI og en kommandolinjegrænseflade (CLI) til styring af OSGi-containeren og dens bundter.

Den første ting du skal gøre er at downloade Knoplerfish. Den aktuelle version på tidspunktet for denne skrivning er Knoplerfish OSGi 6.1.3. Du kan erstatte den version med det, der er mest aktuelt, når du læser denne artikel.

Når du har downloadet og installeret Knoplerfish, skal du bruge CLI til at komme ind i den mappe, hvor du downloadede JAR-filen, og indtaste: java -jar framework.jar. Det kører den eksekverbare JAR, og du skal hilses med et GUI-vindue.

Knoplerfish OSGi GUI

Knoplerfish OSGis GUI kan virke overvældende i starten, men det grundlæggende er simpelt:

  • Øverst på skærmen er menuen.
  • Til venstre er det sæt bundter, der er indlæst i løbetiden.
  • Til højre er et informationsvindue.
  • Nederst er der en tekstoutputkonsol.
  • Nederst er der en indgangskonsol.
Matthew Tyson

Type Hjælp ind i inputkonsollen, hvis du vil se hjælpemulighederne.

Inden vi går ind i eksemplet, skal du se på sættet med kørende bundter. Du vil se et bundt kaldet HTTP-server, hvilket betyder, at et bundt, der kører en HTTP-server, er op. Gå til din browser, og tjek // localhost: 8080. Sikker nok vil du se en Knoplerfish-webside.

'Hello JavaWorld'-pakken

Lad os bruge OSGi-runtime til at opbygge en simpel pakke, som jeg vil kalde Hej JavaWorld. Denne pakke udsender en besked til konsollen.

I lister 1 bruger vi Maven til at oprette pakken. Det har kun en afhængighed, som leveres af OSGi-alliancen.

Liste 1. OSGi-afhængighed i Maven POM

   org.osgi org.osgi.core 

Nu skal vi også bruge et plug-in med tilladelse til Apache Felix-projektet. Denne plug-in tager sig af emballering af appen som et OSGi-bundt til brug. Liste 2 viser den konfiguration, vi bruger.

Notering 2. OSGi Felix-plug-in i Maven POM

   org.apache.felix maven-bundle-plugin sand org.javaworld.osgi org.javaworld.osgi.Hello 

Nu kan vi tage et kig på den enkle klasse, der udsender et "Hej".

Liste 3. Hej JavaWorld OSGi-pakke

 pakke com.javaworld.osgi; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; offentlig klasse HelloJavaWorld implementerer BundleActivator {offentlig ugyldig start (BundleContext ctx) {System.out.println ("Hej JavaWorld."); } offentligt ugyldigt stop (BundleContext bundleContext) {}} 

Byg pakken ved at gå til kommandolinjen og skrive mvn ren installation. Dette udsender en JAR-fil, der indeholder pakken. Gå nu til Fil menu i Knoplerfish GUI, og vælg Tilføj pakke. Dette giver en filbrowser. Find den JAR, vi lige har bygget, og vælg den.

Administration af OSGi-bundter i containeren

I outputvinduet i Knoplerfish UI ser du din "Hej, JavaWorld" -meddelelse vises. Klik på bundtet i Knoplerfish GUI, og du kan se det id, containeren har tildelt det. Når du er klar til at stoppe pakken, kan du klikke på menupunktet Stop. En anden måde er at komme ind stop [bundt nummer] på kommandolinjen. Du kan administrere bundter i containeren ved hjælp af enten GUI eller kommandolinjen.

Nu har du en fornemmelse af, hvordan en simpel pakke fungerer i OSGi-containeren. Overalt hvor der findes en OSGi-container, finder du den samme enkelhed i at starte og stoppe bundter. OSGi skaber et miljø og en livscyklus for pakken.

Bundtinteraktioner: Tjenester og klienter

Dernæst ser vi på, hvordan bundter kommunikerer med hinanden.

Den første ting, vi skal gøre, er at oprette en servicepakke. Et servicepakke er analogt med en EJB-sessionbønne: Det giver en komponent, som andre bundter kan få adgang til via en ekstern grænseflade. For at oprette et servicepakke skal vi give både en grænseflade og en implementeringsklasse.

Fortegnelse 4. Servicepakkegrænsefladen

 pakke com.javaworld.osgi.service; offentlig grænseflade WhatIsOsgi {public Integer addNum (Integer x, Integer y); } 

Listing 4 er en simpel grænseflade. Den eneste metode er en addNum () metode, der vil gøre, hvad den indebærer: returner tilføjelsen af ​​to tal. Implementeringen vist i Listing 5 er lige så enkel, men tilføjer et par OSGi-specifikke metoder.

Liste 5. Implementering af servicebundt

 pakke com.javaworld.osgi.service; offentlig klasse WhatIsOsgiImpl implementerer WhatIsOsgi, BundleActivator {privat ServiceReference ref; privat ServiceRegistration reg; @Override public Integer addNum (Integer x, Integer y) {return x + y; } @ Override offentlig ugyldig start (BundleContext-kontekst) kaster Undtagelse {reg = context.registerService (WhatIsOsgi.class, ny WhatIsOsgiImpl (), ny Hashtable ()); ref = reg.getReference (); } @ Override offentligt ugyldigt stop (BundleContext-kontekst) kaster undtagelse {reg.unregister (); }} 

Lad os se nærmere på, hvad der sker i Listing 5:

  1. offentlig klasse WhatIsOsgiImpl implementerer WhatIsOsgi, BundleActivator: Her implementerer vi den grænseflade, vi oprettede. Bemærk, at vi også implementerer BundleActivator interface, som vi gjorde med HejJavaWorld eksempel. Sidstnævnte skyldes, at denne pakke vil aktivere sig selv.
  2. privat ServiceReference ref; privat ServiceRegistration reg;: Disse er variabler for henholdsvis OSGi-registreringstjenesten og bundtreferencen for denne tjeneste.
  3. public Integer addNum (Integer x, Integer y): Dette er den enkle implementering af add-metoden.
  4. offentlig ugyldig start (BundleContext context): Denne startmetode er en del af BundleActivator interface og udføres af containeren. I dette eksempel får vi en henvisning til OSGi-registreringstjenesten og anvender den på vores WhatIsOsgi interface og implementering. Den tomme Hashtable er til konfigurationsparametre, som vi ikke bruger her. Vi får også en henvisning til den service, vi netop har oprettet.
  5. offentligt ugyldigt stop (BundleContext-kontekst): Her afmelder vi simpelthen tjenesten. Denne enkle tjeneste administrerer bare de bareste elementer i sin livscyklus. Dens hovedformål er at afsløre addNum metode til OSGi-containeren.

OSGi-klienten

Lad os derefter skrive en klient, der kan bruge tjenesten. Denne klient vil igen gøre brug af BundleActivator interface. Det vil også tilføje ServiceListener interface, som vist i liste 6.

Fortegnelse 6. OSGi-serviceklientpakken

 offentlig klasse OsgiClient implementerer BundleActivator, ServiceListener {private BundleContext ctx; privat ServiceReference-service; offentlig ugyldig start (BundleContext ctx) {this.ctx = ctx; prøv {ctx.addServiceListener (dette, "(objectclass =" + WhatIsOsgi.class.getName () + ")"); } fange (InvalidSyntaxException ise) {ise.printStackTrace (); }}} 

Listing 6 har en startmetode, der tilføjer en servicelytter. Denne lytter filtreres efter klassenavnet på den service, vi oprettede i Listing 5. Når tjenesten opdateres, kalder den serviceChanged () metode, som vist i liste 7.

Listing 7. serviceChanged metode

 public void serviceChanged (ServiceEvent event) {int type = event.getType (); switch (type) {case (ServiceEvent.REGISTERED): serviceReference = event.getServiceReference (); Greeter service = (Greeter) (ctx.getService (service)); System.out.println ("Tilføjelse af 10 og 100:" + service.addNum (10, 100)); pause; sag (ServiceEvent.UNREGISTERING): System.out.println ("Tjeneste uregistreret."); ctx.ungetService (event.getServiceReference ()); // frigiver henvisning til service, så det kan være GC'd break; standard: pause; }} 

Bemærk, at serviceChanged metoden bruges til at bestemme, hvilken begivenhed der er sket for en tjeneste, vi er interesseret i. Tjenesten svarer derefter som specificeret. I dette tilfælde, når REGISTRERET begivenhed vises, vi gør brug af addNum () metode.

OSGi-alternativet

Dette har været en hurtig introduktion til OSGi, Open Services Gateway Initiative. Som du har set igennem Knoplerfish-eksemplet, giver OSGi et runtime-miljø, hvor du kan definere modulære Java-komponenter (bundter). Det giver en defineret livscyklus til hosting af bundter i klienten, og det understøtter bundter, der interagerer som klienter og tjenester i containeren. Alle disse funktioner samlet giver et interessant alternativ til standard Java-driftstider og -rammer, især til mobil- og IoT-applikationer.

Endelig skal du bemærke, at den foregående artikel i serien "Hvad er: Java" introducerede Java Platform Module System, som tilbyder en anden tilgang til den samme udfordring ved Java-modulære.

Denne historie, "Hvad er OSGi? En anden tilgang til Java-modularitet" blev oprindeligt udgivet af JavaWorld.