Introduktion til Project Jigsaw

1. Introduktion

Project Jigsaw er et paraplyprojekt med de nye funktioner rettet mod to aspekter:

  • introduktion af modulsystem på Java-sproget
  • og dens implementering i JDK kilde og Java runtime

I denne artikel introducerer vi dig til Jigsaw-projektet og dets funktioner og afslutter det til sidst med en simpel modulær applikation.

2. Modularitet

Kort sagt, modularitet er et designprincip, der hjælper os med at opnå:

  • løs kobling mellem komponenter
  • klare kontrakter og afhængigheder mellem komponenter
  • skjult implementering ved hjælp af stærk indkapsling

2.1. Enhed af modularitet

Nu kommer spørgsmålet om, hvad der er enheden for modularitet? I Java-verdenen, især med OSGi, blev JAR betragtet som enheden for modularitet.

JAR'er hjalp med at gruppere de relaterede komponenter sammen, men de har nogle begrænsninger:

  • eksplicitte kontrakter og afhængigheder mellem JAR'er
  • svag indkapsling af elementer inden for JAR'erne

2.2. JAR helvede

Der var et andet problem med JAR'er - JAR helvede. Flere versioner af JAR'erne, der lå på klassestien, resulterede i ClassLoader indlæser den første fundne klasse fra JAR med meget uventede resultater.

Det andet problem med JVM ved hjælp af classpath var, at kompilering af applikationen ville være vellykket, men applikationen mislykkes ved kørsel med ClassNotFoundExceptionpå grund af de manglende JAR'er på klassestien ved kørsel.

2.3. Ny enhed for modularitet

Med alle disse begrænsninger kom Java-sprogskaberne, når de bruger JAR som enheden for modularitet, med en ny konstruktion på det sprog, der kaldes moduler. Og med dette er der planlagt et helt nyt modulært system til Java.

3. Projektpuslespil

De primære motiver for dette projekt er:

  • oprette et modulsystem til sproget - implementeret under JEP 261
  • anvende det på JDK-kilden - implementeret under JEP 201
  • moduler JDKbiblioteker - implementeret under JEP 200
  • opdater kørselstiden for at understøtte modularitet - implementeret under JEP 220
  • være i stand til at oprette mindre driftstid med et undersæt af moduler fra JDK - implementeret under JEP 282

Et andet vigtigt initiativ er at indkapsle de interne API'er i JDK, dem der er under sol.* pakker og andre ikke-standard API'er. Disse API'er var aldrig beregnet til at blive brugt af offentligheden og var aldrig planlagt at blive vedligeholdt. Men kraften i disse API'er fik Java-udviklerne til at udnytte dem i udviklingen af ​​forskellige biblioteker, rammer og værktøjer. Der har været udskiftninger til få interne API'er, og de andre er flyttet til interne moduler.

4. Nye værktøjer til modularitet

  • jdeps - hjælper med at analysere kodebasen til at identificere afhængigheder af JDK API'er og tredjeparts JAR'er. Det nævner også navnet på modulet, hvor JDK API kan findes. Dette gør det lettere at modulere kodebasen
  • jdeprscan - hjælper med at analysere kodebasen til brug af eventuelle forældede API'er
  • jlink - hjælper med at skabe en mindre runtime ved at kombinere applikationens og JDK's moduler
  • jmod - hjælper med at arbejde med jmod filer. jmod er et nyt format til emballering af modulerne. Dette format tillader inkludering af indbygget kode, konfigurationsfiler og andre data, der ikke passer ind i JAR-filer

5. Modulsystemarkitektur

Modulsystemet, der er implementeret på sproget, understøtter disse som en topniveaukonstruktion, ligesom pakker. Udviklere kan organisere deres kode i moduler og erklære afhængigheder mellem dem i deres respektive moduldefinitionsfiler.

En moduldefinitionsfil, navngivet som modul-info.java, indeholder:

  • dens navn
  • de pakker, den stiller til rådighed offentligt
  • de moduler det afhænger af
  • eventuelle tjenester, den bruger
  • enhver implementering af den service, den leverer

De sidste to emner i ovenstående liste bruges ikke almindeligt. De bruges kun, når tjenester leveres og forbruges via java.util.ServiceLoader interface.

En generel struktur for modulet ser ud som:

src | ---- com.baeldung.reader | | ---- modul-info.java | | ---- com | | ---- baeldung | | ---- læser | | ---- Test.java | ---- com.baeldung.writer | ---- module-info.java | ---- com | ---- baeldung | ---- forfatter | --- -AnotherTest.java

Ovenstående illustration definerer to moduler: com.baeldung.reader og com.baeldung.writer. Hver af dem har sin definition specificeret i modul-info.java og kodefiler placeret under com / baeldung / læser og com / baeldung / forfatter, henholdsvis.

5.1. Modul Definition Terminologier

Lad os se på nogle af terminologierne; vi vil bruge, når vi definerer modulet (dvs. inden for module-info.java):

  • modul: modulets definitionsfil starter med dette nøgleord efterfulgt af dets navn og definition
  • kræver: bruges til at angive de moduler, det afhænger af; et modulnavn skal angives efter dette nøgleord
  • transitiv: er angivet efter kræver nøgleord dette betyder, at ethvert modul, der afhænger af, at modulet definerer kræver transitiv får en implicit afhængighed af <modulnavn>
  • eksport: bruges til at indikere pakkerne inden for modulet tilgængelige offentligt; et pakkenavn skal angives efter dette nøgleord
  • åbner: bruges til at angive de pakker, der kun er tilgængelige under kørsel og også tilgængelige til introspektion via Reflection API'er; dette er ret vigtigt for biblioteker som Spring og Hibernate, i høj grad afhængig af Reflection API'er; åbner kan også bruges på modulniveau, i hvilket tilfælde hele modulet er tilgængeligt under kørsel
  • anvendelser: bruges til at indikere den servicegrænseflade, som dette modul bruger; et type navn, dvs. komplet klasse / interface navn, skal angives efter dette nøgleord
  • giver ... med ...: de bruges til at angive, at det giver implementeringer, identificeret efter med nøgleord til den servicegrænseflade, der er identificeret efter giver nøgleord

6. Enkel modulær applikation

Lad os oprette en simpel modulær applikation med moduler og deres afhængighed som angivet i nedenstående diagram:

Det com.baeldung.student.model er rodmodulet. Det definerer modelklasse com.baeldung.student.model.Student, der indeholder følgende egenskaber:

offentlig klasse Student {privat String registrationId; // andre relevante felter, getters og setters}

Det giver andre moduler med typer defineret i com.baeldung.student.model pakke. Dette opnås ved at definere det i filen modul-info.java:

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

Det com.baeldung.student.service modul giver en grænseflade com.baeldung.student.service.StudentService med abstrakte CRUD-operationer:

offentlig grænseflade StudentService {public String create (Student student); offentlig studerendes læsning (String registrationId); offentlig opdatering af studerende (studerende) offentlig sletning af streng (strengregistreringId); }

Det afhænger af com.baeldung.student.model modul og gør de typer, der er defineret i pakken com.baeldung.student.service tilgængelig for andre moduler:

modul com.baeldung.student.service {kræver transitiv com.baeldung.student.model; eksporterer com.baeldung.student.service; }

Vi leverer et andet modul com.baeldung.student.service.dbimpl, som giver implementeringen com.baeldung.student.service.dbimpl.StudentDbService til ovenstående modul:

offentlig klasse StudentDbService implementerer StudentService {public String create (Student student) {// Oprettelse af studerende i DB returnerer student.getRegistrationId (); } offentlig studenterlæsning (String registrationId) {// Læserelev fra DB returnerer ny elev (); } offentlig studentopdatering (studerende) {// Opdatering af studerende i DB-returstuderende; } offentlig sletning af streng (String registrationId) {// Sletning af studerende i DB returnerer registreringId; }}

Det afhænger direkte af com.baeldung.student.service og transitivt videre com.baeldung.student.model og dens definition vil være:

modul com.baeldung.student.service.dbimpl {kræver transitiv com.baeldung.student.service; kræver java.logging; eksporterer com.baeldung.student.service.dbimpl; }

Det endelige modul er et klientmodul - der udnytter serviceimplementeringsmodulet com.baeldung.student.service.dbimpl at udføre sine operationer:

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

Og dens definition er:

modul com.baeldung.student.client {kræver com.baeldung.student.service.dbimpl; }

7. Kompilering og kørsel af prøven

Vi har leveret scripts til kompilering og kørsel af ovenstående moduler til Windows og Unix-platformene. Disse kan findes under core-java-9 projekt her. Rækkefølgen for udførelse af Windows-platformen er:

  1. kompilere-studerende-model
  2. kompilere-studerende-service
  3. kompilere-studerende-service-dbimpl
  4. kompilere-studerende-klient
  5. run-student-client

Rækkefølgen for udførelse af Linux-platformen er ret enkel:

  1. kompil-moduler
  2. run-student-client

I ovenstående scripts vil du blive introduceret til følgende to kommandolinjeargumenter:

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

Java 9 fjerner begrebet classpath og introducerer i stedet modulstien. Denne sti er det sted, hvor modulerne kan opdages.

Vi kan indstille dette ved hjælp af kommandolinjeargumentet: –Modul-sti.

For at kompilere flere moduler på én gang benytter vi os af –Modul-kilde-sti. Dette argument bruges til at angive placeringen for modulets kildekode.

8. Modulsystem Anvendt på JDK-kilde

Hver JDK-installation leveres med en src.zip. Dette arkiv indeholder kodebasen til JDK Java API'erne. Hvis du udpakker arkivet, finder du flere mapper, hvoraf få starter med java, få med javafx og resten med jdk. Hver mappe repræsenterer et modul.

Modulerne starter med java er JDK-modulerne, dem der starter med javafx er JavaFX-modulerne og andre, der starter med jdk er JDK-værktøjsmodulerne.

Alle JDK-moduler og alle brugerdefinerede moduler afhænger implicit af java.base modul. Det java.base modul indeholder almindeligt anvendte JDK API'er som Utils, Collections, IO, Concurrency blandt andre. Afhængighedsgrafen for JDK-modulerne er:

Du kan også se på definitionerne af JDK-modulerne for at få en idé om syntaksen til at definere dem i modul-info.java.

9. Konklusion

I denne artikel så vi på at oprette, kompilere og køre en simpel modulær applikation. Vi så også, hvordan JDK-kildekoden var blevet moduleret.

Der er få flere spændende funktioner, som at oprette mindre runtime ved hjælp af linker-værktøjet - jlink og oprette modulære krukker blandt andre funktioner. Vi introducerer dig til disse funktioner i detaljer i fremtidige artikler.

Project Jigsaw er en enorm forandring, og vi bliver nødt til at vente og se, hvordan det bliver accepteret af udviklerens økosystem, især med værktøjerne og biblioteksskaberne.

Koden, der bruges i denne artikel, kan findes på GitHub.