Introduksjon til Project Jigsaw

1. Introduksjon

Project Jigsaw er et paraplyprosjekt med de nye funksjonene rettet mot to aspekter:

  • innføring av modulsystem på Java-språket
  • og implementeringen av den i JDK-kilde- og Java-kjøretid

I denne artikkelen vil vi introdusere deg for Jigsaw-prosjektet og dets funksjoner, og til slutt avslutte det med en enkel modulær applikasjon.

2. Modularitet

Enkelt sagt, modularitet er et designprinsipp som hjelper oss å oppnå:

  • løs kobling mellom komponentene
  • klare kontrakter og avhengigheter mellom komponenter
  • skjult implementering ved hjelp av sterk innkapsling

2.1. Enhet for modularitet

Nå kommer spørsmålet om hva som er enheten for modularitet? I Java-verdenen, spesielt med OSGi, ble JAR betraktet som enheten for modularitet.

JAR hjalp til med å gruppere de relaterte komponentene sammen, men de har noen begrensninger:

  • eksplisitte kontrakter og avhengigheter mellom JAR
  • svak innkapsling av elementer innen JAR

2.2. JAR helvete

Det var et annet problem med JAR-helvete. Flere versjoner av JARene som lå på klassestien, resulterte i at ClassLoader laster den første funnet klassen fra JAR, med svært uventede resultater.

Det andre problemet med JVM ved bruk av classpath var at kompilering av applikasjonen ville lykkes, men applikasjonen mislykkes ved kjøretid med ClassNotFoundException, på grunn av manglende JAR på klassestien ved kjøretid.

2.3. Ny enhet for modularitet

Med alle disse begrensningene, når JAR som enhet for modularitet, kom Java-språkskaperne med en ny konstruksjon på språket som kalles moduler. Og med dette er det planlagt et helt nytt modulsystem for Java.

3. Prosjekt stikksag

De viktigste motivasjonene for dette prosjektet er:

  • lage et modulsystem for språket - implementert under JEP 261
  • bruk den på JDK-kilden - implementert under JEP 201
  • moduler JDKbiblioteker - implementert under JEP 200
  • oppdater kjøretiden for å støtte modularitet - implementert under JEP 220
  • kunne lage mindre kjøretid med et delsett av moduler fra JDK - implementert under JEP 282

Et annet viktig initiativ er å kapsle de interne API-ene i JDK, de som er under sol.* pakker og andre ikke-standard APIer. Disse API-ene var aldri ment å brukes av publikum og var aldri planlagt å vedlikeholdes. Men kraften til disse API-ene gjorde at Java-utviklerne utnyttet dem i utviklingen av forskjellige biblioteker, rammer og verktøy. Det har blitt gitt erstatninger for få interne API-er, og de andre er flyttet til interne moduler.

4. Nye verktøy for modularitet

  • jdeps - hjelper med å analysere kodebasen for å identifisere avhengighetene til JDK APIer og tredjeparts JARer. Det nevner også navnet på modulen der JDK API kan bli funnet. Dette gjør det lettere å modulere kodebasen
  • jdeprscan - hjelper med å analysere kodebasen for bruk av eventuelle utdaterte API-er
  • jlink - hjelper til med å skape en mindre kjøretid ved å kombinere applikasjonens og JDKs moduler
  • jmod - hjelper til med å jobbe med jmod-filer. jmod er et nytt format for pakking av modulene. Dette formatet gjør det mulig å inkludere innebygd kode, konfigurasjonsfiler og andre data som ikke passer inn i JAR-filer

5. Modulsystemarkitektur

Modulsystemet, implementert på språket, støtter disse som en toppnivåkonstruksjon, akkurat som pakker. Utviklere kan organisere koden i moduler og erklære avhengighet mellom dem i deres respektive moduldefinisjonsfiler.

En moduldefinisjonsfil, kalt module-info.java, inneholder:

  • dets navn
  • pakkene den gjør tilgjengelig offentlig
  • modulene det avhenger av
  • eventuelle tjenester den bruker
  • enhver implementering for tjenesten den tilbyr

De to siste elementene i listen ovenfor brukes ikke ofte. De brukes bare når tjenester blir levert og konsumert via java.util.ServiceLoader grensesnitt.

En generell struktur for modulen ser ut som:

src | ---- com.baeldung.reader | | ---- module-info.java | | ---- com | | ---- baeldung | | ---- leser | | ---- Test.java | ---- com.baeldung.writer | ---- module-info.java | ---- com | ---- baeldung | ---- skribent | --- -AnotherTest.java

Illustrasjonen ovenfor definerer to moduler: com.baeldung.reader og com.baeldung.writer. Hver av dem har sin definisjon spesifisert i module-info.java og kodefilene plassert under com / baeldung / reader og com / baeldung / skribent, henholdsvis.

5.1. Modul Definisjon Terminologier

La oss se på noen av terminologiene; vi vil bruke mens vi definerer modulen (dvs. innenfor module-info.java):

  • modul: moduldefinisjonsfilen starter med dette nøkkelordet etterfulgt av navnet og definisjonen
  • krever: brukes til å indikere modulene det avhenger av; et modulnavn må spesifiseres etter dette nøkkelordet
  • transitive: er spesifisert etter krever nøkkelord; dette betyr at en hvilken som helst modul som er avhengig av at modulen definerer krever transitive får en implisitt avhengighet av <modulnavn>
  • eksport: brukes til å indikere pakkene i modulen tilgjengelig offentlig; et pakkenavn må spesifiseres etter dette nøkkelordet
  • åpnes: brukes til å indikere pakkene som bare er tilgjengelige i løpetid og også tilgjengelig for introspeksjon via Reflection APIs; dette er ganske viktig for biblioteker som Spring og Hibernate, og er sterkt avhengig av Reflection APIer; åpnes kan også brukes på modulnivå, i så fall er hele modulen tilgjengelig på kjøretid
  • bruker: brukes til å indikere tjenestegrensesnittet som denne modulen bruker; et typenavn, dvs. komplett klasse / grensesnittnavn, må spesifiseres etter dette nøkkelordet
  • gir ... med ...: de brukes til å indikere at det gir implementeringer, identifisert etter med nøkkelord, for tjenestegrensesnittet som er identifisert etter gir nøkkelord

6. Enkel modulær applikasjon

La oss lage en enkel modulær applikasjon med moduler og deres avhengighet som angitt i diagrammet nedenfor:

De com.baeldung.student.model er rotmodulen. Den definerer modellklasse com.baeldung.student.model.Student, som inneholder følgende egenskaper:

offentlig klasse Student {private String registrationId; // andre relevante felt, getters og setters}

Den gir andre moduler med typer definert i com.baeldung.student.model pakke. Dette oppnås ved å definere det i filen module-info.java:

module com.baeldung.student.model {eksporterer com.baeldung.student.model; }

De com.baeldung.student.service modulen gir et grensesnitt com.baeldung.student.service.StudentService med abstrakte CRUD-operasjoner:

offentlig grensesnitt StudentService {public String create (Student student); offentlig Studentlesning (String registrationId); offentlig studentoppdatering (studentstudent); offentlig sletting av streng (String registrationId); }

Det kommer an på com.baeldung.student.model modul og lager typene som er definert i pakken com.baeldung.student.service tilgjengelig for andre moduler:

modul com.baeldung.student.service {krever transitiv com.baeldung.student.model; eksporterer com.baeldung.student.service; }

Vi tilbyr en annen modul com.baeldung.student.service.dbimpl, som gir implementeringen com.baeldung.student.service.dbimpl.StudentDbService for ovennevnte modul:

offentlig klasse StudentDbService implementerer StudentService {public String create (Student student) {// Opprette student i DB returner student.getRegistrationId (); } public Student read (String registrationId) {// Reading student from DB return new Student (); } offentlig studentoppdatering (studentstudent) {// Oppdatering av student i DB-returstudent; } public String delete (String registrationId) {// Slette student i DB return registreringId; }}

Det kommer direkte an på com.baeldung.student.service og transitt videre com.baeldung.student.model og dens definisjon vil være:

modul com.baeldung.student.service.dbimpl {krever transitiv com.baeldung.student.service; krever java.logging; eksporterer com.baeldung.student.service.dbimpl; }

Den endelige modulen er en klientmodul - som utnytter tjenestens implementeringsmodul com.baeldung.student.service.dbimpl for å utføre sine operasjoner:

public class StudentClient {public static void main (String [] args) {StudentService service = new StudentDbService (); service.create (ny student ()); service.read ("17SS0001"); service.update (ny student ()); service.delete ("17SS0001"); }}

Og dens definisjon er:

modul com.baeldung.student.client {krever com.baeldung.student.service.dbimpl; }

7. Kompilering og kjøring av prøven

Vi har gitt skript for å kompilere og kjøre ovennevnte moduler for Windows og Unix-plattformene. Disse finner du under core-java-9 prosjekt her. Bestillingsrekkefølgen for Windows-plattformen er:

  1. kompilere-student-modell
  2. kompilere-student-tjeneste
  3. kompilere-student-tjeneste-dbimpl
  4. kompilere-student-klient
  5. run-student-client

Rekkefølgen for Linux-plattformen er ganske enkel:

  1. kompilere moduler
  2. run-student-client

I skriptene ovenfor vil du bli introdusert for følgende to kommandolinjeargumenter:

  • –Modul-kilde-bane
  • –Modul-sti

Java 9 fjerner begrepet classpath og introduserer i stedet modulbanen. Denne banen er stedet der modulene kan oppdages.

Vi kan sette dette ved å bruke kommandolinjeargumentet: –Modul-sti.

For å kompilere flere moduler samtidig bruker vi –Modul-kilde-bane. Dette argumentet brukes til å oppgi plasseringen for modulens kildekode.

8. Modulsystem brukt på JDK Source

Hver JDK-installasjon leveres med en src.zip. Dette arkivet inneholder kodebasen for JDK Java API-ene. Hvis du trekker ut arkivet, finner du flere mapper, noen starter med java, få med javafx og resten med jdk. Hver mappe representerer en modul.

Modulene starter med java er JDK-modulene, de som begynner med javafx er JavaFX-modulene og andre som begynner med jdk er JDK-verktøymodulene.

Alle JDK-moduler og alle brukerdefinerte moduler avhenger implisitt av java.base modul. De java.base modulen inneholder ofte brukte JDK APIer som Utils, Collections, IO, Concurrency blant andre. Avhengighetsgrafen til JDK-modulene er:

Du kan også se på definisjonene av JDK-modulene for å få en ide om syntaksen for å definere dem i module-info.java.

9. Konklusjon

I denne artikkelen så vi på å lage, kompilere og kjøre en enkel modulær applikasjon. Vi så også hvordan JDK-kildekoden hadde blitt modulert.

Det er få flere spennende funksjoner, som å lage mindre kjøretid ved hjelp av lenkeverktøyet - jlink og lage modulære krukker blant andre funksjoner. Vi vil introdusere deg for disse funksjonene i detaljer i fremtidige artikler.

Project Jigsaw er en stor forandring, og vi må vente og se hvordan det blir akseptert av utviklerens økosystem, spesielt med verktøyene og bibliotekskaperne.

Koden som brukes i denne artikkelen finner du på GitHub.