Mikrotjenester med Oracle Helidon

1. Oversigt

Helidon er den nye Java-mikroservice-ramme, der for nylig er åben fra Oracle. Det blev brugt internt i Oracle-projekter under navnet J4C (Java for Cloud).

I denne vejledning dækker vi de vigtigste begreber i rammen, og derefter bevæger vi os for at opbygge og køre en Helidon-baseret mikroservice.

2. Programmeringsmodel

I øjeblikket, rammen understøtter to programmeringsmodeller til skrivning af mikrotjenester: Helidon SE og Helidon MP.

Mens Helidon SE er designet til at være et mikroframework, der understøtter den reaktive programmeringsmodel, er Helidon MP på den anden side en Eclipse MicroProfile runtime, der gør det muligt for Jakarta EE-samfundet at køre mikrotjenester på en bærbar måde.

I begge tilfælde er en Helidon-mikroservice et Java SE-program, der starter en tinny HTTP-server fra hovedmetoden.

3. Helidon SE

I dette afsnit opdager vi i flere detaljer hovedkomponenterne i Helidon SE: WebServer, Config og Security.

3.1. Opsætning af WebServer

For at komme i gang med WebServer API, vi er nødt til at tilføje den krævede Maven afhængighed til pom.xml fil:

 io.helidon.webserver helidon-webserver 0.10.4 

At have en simpel webapplikation, vi kan bruge en af ​​følgende bygningsmetoder: WebServer.create (serverConfig, routing) eller bare WebServer.create (routing). Den sidste tager en standardserverkonfiguration, der gør det muligt for serveren at køre på en tilfældig port.

Her er en simpel webapplikation, der kører på en foruddefineret port. Vi har også registreret en simpel handler, der vil svare med en hilsen til enhver HTTP-anmodning med '/hilse' sti og Metode:

offentlig statisk ugyldig hoved (String ... args) kaster Undtagelse {ServerConfiguration serverConfig = ServerConfiguration.builder () .port (9001) .build (); Routing routing = Routing.builder () .get ("/ greet", (anmodning, svar) -> response.send ("Hello World!")). Build (); WebServer.create (serverConfig, routing) .start () .thenAccept (ws -> System.out.println ("Server startet ved: // localhost:" + ws.port ())); }

Den sidste linje er at starte serveren og vente på servering af HTTP-anmodninger. Men hvis vi kører denne prøvekode i hovedmetoden, får vi fejlen:

Undtagelse i tråden "main" java.lang.IllegalStateException: Ingen implementering fundet for SPI: io.helidon.webserver.spi.WebServerFactory

Det Webserver er faktisk et SPI, og vi skal levere en runtime-implementering. I øjeblikket, Helidon leverer NettyWebServer implementering som er baseret på Netty Core.

Her er Maven-afhængigheden af ​​denne implementering:

 io.helidon.webserver helidon-webserver-netty 0.10.4 runtime 

Nu kan vi køre hovedapplikationen og kontrollere, at den fungerer ved at påkalde det konfigurerede slutpunkt:

// localhost: 9001 / hilsen

I dette eksempel konfigurerede vi både porten og stien ved hjælp af bygmønsteret.

Helidon SE tillader også brug af et konfigurationsmønster, hvor konfigurationsdataene leveres af Konfig API. Dette er emnet for det næste afsnit.

3.2. Det Konfig API

Det Konfig API giver værktøjer til at læse konfigurationsdata fra en konfigurationskilde.

Helidon SE leverer implementeringer til mange konfigurationskilder. Standardimplementeringen leveres af helidon-config hvor konfigurationskilden er en application.properties fil placeret under klassestien:

 io.helidon.config helidon-config 0.10.4 

For at læse konfigurationsdataene skal vi bare bruge standardbyggeren, der som standard tager konfigurationsdataene fra application.properties:

Config config = Config.builder (). Build ();

Lad os oprette en application.properties fil under src / main / resource bibliotek med følgende indhold:

server.port = 9080 web.debug = sand web.page-size = 15 user.home = C: / Brugere / app

For at læse værdierne kan vi bruge Config.get () metode efterfulgt af en praktisk casting til de tilsvarende Java-typer:

int port = config.get ("server.port"). asInt (); int pageSize = config.get ("web.page-size"). asInt (); boolsk debug = config.get ("web.debug"). asBoolean (); String userHome = config.get ("user.home"). AsString ();

Faktisk indlæser standardbyggeren den første fundne fil i denne prioritetsrækkefølge: application.yaml, application.conf, application.json og application.properties. De sidste tre format har brug for en ekstra relateret konfigurationsafhængighed. For eksempel for at bruge YAML-formatet skal vi tilføje den relaterede YAML-konfigurationsafhængighed:

 io.helidon.config helidon-config-yaml 0.10.4 

Og så tilføjer vi en ansøgning.yml:

server: port: 9080 web: debug: ægte sidestørrelse: 15 bruger: hjem: C: / Brugere / app

For at bruge CONF, som er et JSON-forenklet format eller JSON-formater, skal vi tilføje helidon-config-hocon-afhængighed.

Bemærk, at konfigurationsdataene i disse filer kan tilsidesættes af miljøvariabler og Java-systemegenskaber.

Vi kan også kontrollere standardbyggerens opførsel ved at deaktivere miljøvariabler og systemegenskaber eller ved eksplicit at angive konfigurationskilden:

ConfigSource configSource = ConfigSources.classpath ("application.yaml"). Build (); Config config = Config.builder () .disableSystemPropertiesSource () .disableEnvironmentVariablesSource () .sources (configSource) .build ();

Ud over at læse konfigurationsdata fra klassestien kan vi også bruge to eksterne kildekonfigurationer, det vil sige git- og etcd-konfigurationerne. Til dette har vi brug for afhængigheden af ​​helidon-config-git og helidon-git-etcd.

Endelig, hvis alle disse konfigurationskilder ikke tilfredsstiller vores behov, tillader Helidon os at levere en implementering af vores konfigurationskilde. For eksempel kan vi levere en implementering, der kan læse konfigurationsdataene fra en database.

3.3. Det Routing API

Det Routing API giver den mekanisme, hvormed vi binder HTTP-anmodninger til Java-metoder. Vi kan opnå dette ved at bruge anmodningsmetoden og stien som matchende kriterier eller RequestPredicate objekt til at bruge flere kriterier.

Så for at konfigurere en rute kan vi bare bruge HTTP-metoden som kriterier:

Routing routing = Routing.builder () .get ((anmodning, svar) -> {});

Eller vi kan kombinere HTTP-metoden med anmodningsstien:

Routing routing = Routing.builder () .get ("/ sti", (anmodning, svar) -> {});

Vi kan også bruge RequestPredicate for mere kontrol. For eksempel kan vi se efter en eksisterende overskrift eller for indholdstypen:

Routing routing = Routing.builder () .post ("/ save", RequestPredicate.whenRequest () .containsHeader ("header1") .containsCookie ("cookie1") .accepts (MediaType.APPLICATION_JSON) .containsQueryParameter ("param1"). hasContentType ("application / json"). derefter Anvende ((anmodning, svar) -> {}). andet ((anmodning, svar) -> {})) .build ();

Indtil nu har vi leveret håndterere i funktionel stil. Vi kan også bruge Service klasse, der gør det muligt at skrive håndtere på en mere sofistikeret måde.

Så lad os først oprette en model for det objekt, vi arbejder med, the Bestil klasse:

public class Book {privat streng-id; privat strengnavn; privat strengforfatter; private heltalssider; // ...}

Vi kan oprette REST-tjenester til Bestil klasse ved at implementere Service.update () metode. Dette gør det muligt at konfigurere delstier for den samme ressource:

offentlig klasse BookResource implementerer Service {private BookManager bookManager = ny BookManager (); @Override offentlig ugyldig opdatering (Routing.Rules regler) {regler .get ("/", dette :: bøger) .get ("/ {id}", dette :: bookById); } privat ugyldigt bookById (ServerRequest serverRequest, ServerResponse serverResponse) {String id = serverRequest.path (). param ("id"); Bogbog = bookManager.get (id); JsonObject jsonObject = fra (bog); serverResponse.send (jsonObject); } private ugyldige bøger (ServerRequest serverRequest, ServerResponse serverResponse) {List books = bookManager.getAll (); JsonArray jsonArray = fra (bøger); serverResponse.send (jsonArray); } // ...}

Vi har også konfigureret medietypen som JSON, så vi har brug for helidon-webserver-json-afhængighed til dette formål:

 io.helidon.webserver helidon-webserver-json 0.10.4 

Langt om længe, vi bruger Tilmeld() metode til Routing bygherre til at binde rodstien til ressourcen. I dette tilfælde, Stier konfigureret af tjenesten er forud for rodstien:

Routing routing = Routing.builder () .register (JsonSupport.get ()) .register ("/ books", ny BookResource ()) .build ();

Vi kan nu starte serveren og kontrollere slutpunkterne:

// localhost: 9080 / bøger // localhost: 9080 / books / 0001-201810

3.4. Sikkerhed

I dette afsnit, vi skal sikre vores ressourcer ved hjælp af sikkerhedsmodulet.

Lad os starte med at erklære alle de nødvendige afhængigheder:

 io.helidon.security helidon-sikkerhed 0.10.4 io.helidon.security helidon-security-provider-http-auth 0.10.4 io.helidon.security helidon-security-integration-webserver 0.10.4 

Helidon-sikkerhed, helidon-sikkerhedsudbyder-http-auth og helidon-sikkerhed-integration-webserverafhængigheder er tilgængelige fra Maven Central.

Sikkerhedsmodulet tilbyder mange udbydere til godkendelse og godkendelse. I dette eksempel bruger vi HTTP-grundlæggende godkendelsesudbyder da det er ret simpelt, men processen for andre udbydere er næsten den samme.

Den første ting at gøre er at oprette en Sikkerhed eksempel. Vi kan gøre det enten programmatisk for enkelhedens skyld:

Kortbrugere = // ... UserStore butik = bruger -> Valgfri.afNullable (brugere.get (bruger)); HttpBasicAuthProvider httpBasicAuthProvider = HttpBasicAuthProvider.builder () .realm ("myRealm") .subjectType (SubjectType.USER) .userStore (butik) .build (); Sikkerhedssikkerhed = Security.builder () .addAuthenticationProvider (httpBasicAuthProvider) .build ();

Eller vi kan bruge en konfigurationsmetode.

I dette tilfælde erklærer vi al sikkerhedskonfiguration i ansøgning.yml fil, som vi indlæser gennem Konfig API:

#Config 4 Sikkerhed ==> Kortlagt til sikkerhed Objekt sikkerhed: udbydere: - http-basic-auth: realm: "helidon" principaltype: BRUGER # Kan være BRUGER eller SERVICE, standard er BRUGER brugere: - login: "bruger" adgangskode: "bruger" -roller: ["ROLE_USER"] - login: "admin" adgangskode: "admin" -roller: ["ROLE_USER", "ROLE_ADMIN"] #Config 4 Sikkerhed Webserverintegration ==> Kortlagt til WebSecurity Object web- server: securityDefaults: godkende: sande stier: - sti: "/ bruger" -metoder: ["get"] -roller-tilladt: ["ROLE_USER", "ROLE_ADMIN"] - sti: "/ admin" metoder: ["get"] tilladte roller: ["ROLE_ADMIN"]

Og for at indlæse det skal vi bare oprette en Konfig objekt, og så påberåber vi os Security.fromConfig () metode:

Config config = Config.create (); Sikkerhedssikkerhed = Security.fromConfig (config);

Når vi har den Sikkerhed For eksempel skal vi først registrere det med Webserver bruger WebSecurity.from () metode:

Routing routing = Routing.builder () .register (WebSecurity.from (sikkerhed) .securityDefaults (WebSecurity.authenticate ())) .build ();

Vi kan også oprette en Websikkerhed forekomst direkte ved hjælp af konfigurationsmetoden, hvormed vi indlæser både sikkerhed og webserverkonfiguration:

Routing routing = Routing.builder () .register (WebSecurity.from (config)) .build ();

Vi kan nu tilføje nogle håndterere til /bruger og / admin stier, start serveren og prøv at få adgang til dem:

Routing routing = Routing.builder () .register (WebSecurity.from (config)) .get ("/ user", (anmodning, svar) -> response.send ("Hej, jeg er Helidon SE")) .get ("/ admin", (anmodning, svar) -> respons.send ("Hej, jeg er Helidon SE")) .build ();

4. Helidon MP

Helidon MP er en implementering af Eclipse MicroProfile og giver også en kørselstid til kørsel af MicroProfile-baserede mikrotjenester.

Da vi allerede har en artikel om Eclipse MicroProfile, tjekker vi kildekoden og ændrer den til at køre på Helidon MP.

Efter at have tjekket koden fjerner vi alle afhængigheder og plugins og tilføjer Helidon MP-afhængigheder til POM-filen:

 io.helidon.microprofile.bundles helidon-microprofile-1.2 0.10.4 org.glassfish.jersey.media jersey-media-json-binding 2.26 

Helidon-microprofile-1.2 og jersey-media-json-bindende afhængigheder er tilgængelige fra Maven Central.

Næste, vi tilføjer bønner.xml fil under src / main / resource / META-INF vejviser med dette indhold:

I LibraryApplication klasse, tilsidesætte getClasses () metode, så serveren ikke scanner efter ressourcer:

@Override offentligt sæt getClasses () {returner CollectionsHelper.setOf (BookEndpoint.class); }

Til sidst skal du oprette en hovedmetode og tilføje dette kodestykke:

offentlig statisk ugyldig hoved (String ... args) {Server server = Server.builder () .addApplication (LibraryApplication.class) .port (9080) .build (); server.start (); }

Og det er det. Vi er nu i stand til at påkalde alle bogressourcerne.

5. Konklusion

I denne artikel har vi undersøgt hovedkomponenterne i Helidon og også vist, hvordan man opsætter enten Helidon SE og MP. Da Helidon MP kun er en Eclipse MicroProfile-runtime, kan vi køre enhver eksisterende MicroProfile-baseret mikroservice ved hjælp af den.

Som altid kan koden til alle eksemplerne ovenfor findes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found