Sprievodca modularitou Java 9

1. Prehľad

Java 9 predstavuje novú úroveň abstrakcie nad balíkmi, formálne známu ako Java Platform Module System (JPMS) alebo skrátene „Moduly“.

V tomto tutoriáli si prejdeme nový systém a prediskutujeme jeho rôzne aspekty.

Zostavíme tiež jednoduchý projekt na demonštráciu všetkých konceptov, ktoré sa v tejto príručke naučíme.

2. Čo je modul?

Najskôr musíme pochopiť, čo je modul, aby sme pochopili, ako ich používať.

Modul je skupina úzko súvisiacich balíkov a zdrojov spolu s novým súborom deskriptorov modulov.

Inými slovami, ide o abstrakciu „balíka Java Packages“, ktorá nám umožňuje urobiť náš kód ešte viac použiteľným.

2.1. Balíčky

Balíky vo vnútri modulu sú identické s balíkmi Java, ktoré používame od vzniku Java.

Keď vytvoríme modul, kód organizujeme interne v balíkoch, ako sme to robili predtým v prípade iných projektov.

Okrem organizácie nášho kódu sa balíčky používajú na určenie toho, aký kód je verejne prístupný mimo modulu. O tom strávime v tomto článku viac času.

2.2. Zdroje

Každý modul je zodpovedný za svoje zdroje, ako sú médiá alebo konfiguračné súbory.

Predtým sme všetky zdroje vložili na koreňovú úroveň nášho projektu a manuálne spravovali, ktoré zdroje patrili k rôznym častiam aplikácie.

S modulmi môžeme dodávať požadované obrázky a súbory XML s modulom, ktorý to potrebuje, čo uľahčuje správu našich projektov.

2.3. Deskriptor modulu

Keď vytvárame modul, zahrnieme súbor deskriptora, ktorý definuje niekoľko aspektov nášho nového modulu:

  • názov - názov nášho modulu
  • Závislosti - zoznam ďalších modulov, od ktorých tento modul závisí
  • Verejné balíčky - zoznam všetkých balíkov, ku ktorým chceme mať prístup z vonkajšej strany modulu
  • Ponúkané služby - môžeme poskytnúť implementácie služieb, ktoré môžu spotrebovať ďalšie moduly
  • Spotrebované služby - umožňuje, aby bol súčasný modul spotrebiteľom služby
  • Reflexné povolenia - výslovne umožňuje iným triedam používať reflexiu na prístup k súkromným členom balíka

Pravidlá pre pomenovanie modulov sú podobné tomu, ako pomenujeme balíčky (bodky sú povolené, pomlčky nie). Je veľmi bežné robiť buď projektový štýl (my.module), alebo reverzný DNS (com.baeldung.mymodule) názvy štýlov. V tejto príručke použijeme štýl projektu.

Musíme uviesť zoznam všetkých balíkov, ktoré chceme zverejniť, pretože štandardne sú všetky balíčky súkromné.

To isté platí pre reflexiu. V predvolenom nastavení nemôžeme použiť reflexiu na triedy, ktoré importujeme z iného modulu.

Ďalej v článku sa pozrieme na príklady použitia súboru deskriptora modulu.

2.4. Typy modulov

V novom modulovom systéme sú štyri typy modulov:

  • Systémové moduly- Toto sú moduly uvedené pri spustení zoznam-moduly povel hore. Zahŕňajú moduly Java SE a JDK.
  • Aplikačné moduly - Tieto moduly sú to, čo zvyčajne chceme vytvoriť, keď sa rozhodneme používať moduly. Sú pomenované a definované v kompilácii modul-info.trieda súbor zahrnutý v zostavenom JAR.
  • Automatické moduly - Neoficiálne moduly môžeme zahrnúť pridaním existujúcich súborov JAR do cesty k modulu. Názov modulu bude odvodený od názvu JAR. Automatické moduly budú mať plný prístup na čítanie ku všetkým ďalším modulom načítaným cestou.
  • Nepomenovaný modul - Keď sa do cesty triedy načíta trieda alebo JAR, ale nie cesta modulu, automaticky sa pridá do nepomenovaného modulu. Je to univerzálny modul na udržiavanie spätnej kompatibility s predtým napísaným kódom Java.

2.5. Distribúcia

Moduly je možné distribuovať jedným z dvoch spôsobov: ako súbor JAR alebo ako „explodovaný“ kompilovaný projekt. To je samozrejme rovnaké ako akýkoľvek iný projekt Java, takže by nás nemalo prekvapovať.

Môžeme vytvárať viacmodulové projekty zložené z „hlavnej aplikácie“ a niekoľkých knižničných modulov.

Musíme však byť opatrní, pretože na jeden súbor JAR môžeme mať iba jeden modul.

Keď nastavujeme náš zostavovací súbor, musíme sa uistiť, že sme každý modul v našom projekte zoskupili do samostatnej nádoby.

3. Predvolené moduly

Keď inštalujeme Java 9, vidíme, že JDK má teraz novú štruktúru.

Vzali všetky pôvodné balíčky a presunuli ich do nového modulového systému.

To, čo sú tieto moduly, môžeme zistiť zadaním do príkazového riadku:

java --list-moduly

Tieto moduly sú rozdelené do štyroch hlavných skupín: java, javafx, jdk, a Oracle.

java moduly sú implementačnými triedami pre základnú špecifikáciu jazyka SE.

javafx moduly sú knižnice FX UI.

Všetko, čo samotná JDK potrebuje, je uložené v priečinku jdk modulov.

A nakoniec, všetko, čo je špecifické pre Oracle, je v veštec modulov.

4. Vyhlásenia modulov

Ak chcete nastaviť modul, musíme do koreňového adresára našich balíkov vložiť špeciálny súbor modul-info.java.

Tento súbor je známy ako deskriptor modulu a obsahuje všetky údaje potrebné na zostavenie a použitie nášho nového modulu.

Modul zostavíme s vyhlásením, ktorého telo je buď prázdne, alebo zložené z direktív modulu:

modul myModuleName {// všetky smernice sú voliteľné}

Deklaráciu modulu začíname znakom modul kľúčové slovo a riadime sa tým podľa názvu modulu.

Modul bude pracovať s týmto vyhlásením, ale bežne budeme potrebovať viac informácií.

Tu prichádzajú na rad smernice o moduloch.

4.1. Vyžaduje sa

Naša prvá smernica je vyžaduje. Táto modulárna smernica nám umožňuje deklarovať závislosť modulov:

modul my.module {vyžaduje module.name; }

Teraz, môj.modulzávislosť runtime aj kompilácie na názov modulu.

A všetky verejné typy exportované zo závislosti sú prístupné nášmu modulu, keď použijeme túto smernicu.

4.2. Vyžaduje statické

Niekedy napíšeme kód, ktorý odkazuje na iný modul, ale ktorý používatelia našej knižnice nikdy nebudú chcieť použiť.

Napríklad by sme mohli napísať užitočnú funkciu, ktorá pekne vytlačí náš interný stav, keď je prítomný ďalší protokolovací modul. Avšak nie každý spotrebiteľ našej knižnice bude chcieť túto funkcionalitu a nechce zahrnúť ďalšiu knižnicu na prihlásenie.

V týchto prípadoch chceme použiť voliteľnú závislosť. Použitím vyžaduje statické smernice, vytvoríme závislosť iba na kompiláciu:

modul my.module {vyžaduje statický module.name; }

4.3. Vyžaduje sa tranzitívna

Bežne pracujeme s knižnicami, aby sme si uľahčili život.

Musíme sa však ubezpečiť, že akýkoľvek modul, ktorý prinesie náš kód, prinesie aj tieto extra „tranzitívne“ závislosti, inak nebude fungovať.

Našťastie môžeme použiť vyžaduje tranzitívne smernica prinútiť všetkých následných spotrebiteľov, aby si prečítali aj naše požadované závislosti:

modul my.module {vyžaduje tranzitívny module.name; }

Teraz, keď je vývojár vyžaduje môj.modul, nebudú musieť tiež povedať vyžaduje module.name aby náš modul stále fungoval.

4.4. Vývoz

V predvolenom nastavení modul nevystavuje žiadne zo svojich rozhraní API iným modulom. Toto silné zapuzdrenie bol jedným z kľúčových motivátorov pre vytvorenie modulového systému.

Náš kód je podstatne bezpečnejší, ale ak chceme, aby bol použiteľný, musíme otvorene otvoriť naše API svetu.

Používame vývoz smernica vystaviť všetkých verejných členov pomenovaného balíka:

modul my.module {exportuje com.my.package.name; }

Teraz, keď to niekto robí vyžaduje môj.modul, budú mať prístup k verejným typom v našom com.my.package.name balíka, ale nie iného balíka.

4.5. Exportuje ... do

Môžeme použiť exportuje… do otvoriť naše verejné triedy svetu.

Čo však robiť, ak nechceme, aby k nášmu API mal prístup celý svet?

Pomocou modulu môžeme obmedziť, ktoré moduly majú prístup k našim API exportuje… do smernice.

Podobne ako v vývoz smernice deklarujeme balík ako exportovaný. Ďalej však uvádzame, ktoré moduly povoľujeme importovať tento balík ako vyžaduje. Pozrime sa, ako to vyzerá:

modul my.module {export com.my.package.name do com.specific.package; }

4.6. Používa sa

A služby je implementácia konkrétneho rozhrania alebo abstraktnej triedy, ktorá môže byť spotrebované inými triedami.

Sami určujeme služby, ktoré náš modul spotrebúva používa smernice.

Poznač si to názov triedy my použitie je buď rozhranie alebo abstraktná trieda služby, nie implementačná trieda:

modul my.module {používa class.name; }

Tu by sme si mali uvedomiť, že existuje rozdiel medzi a vyžaduje a smernice používa smernice.

Mohli by sme vyžadovať modul, ktorý poskytuje službu, ktorú chceme využívať, ale táto služba implementuje rozhranie z jednej zo svojich tranzitívnych závislostí.

Namiesto toho, aby sme nútili náš modul vyžadovať všetko tranzitívnych závislostí pre každý prípad, použijeme používa smernica na pridanie požadovaného rozhrania k ceste modulu.

4.7. Poskytuje ... s

Modul môže byť tiež a poskytovateľ služieb ktoré môžu spotrebovať iné moduly.

Prvou časťou smernice je poskytuje kľúčové slovo. Tu umiestnime názov rozhrania alebo abstraktnej triedy.

Ďalej tu máme s smernice, kde poskytujeme buď názov implementačnej triedy náradie rozhranie alebo predlžuje abstraktná trieda.

Takto to vyzerá dohromady:

modul my.module {poskytuje MyInterface s MyInterfaceImpl; }

4.8. Otvorené

Už sme spomenuli, že zapuzdrenie bolo hnacím motorom pre návrh tohto modulového systému.

Pred programom Java 9 bolo možné pomocou reflexie preskúmať každý typ a člena v balíku, dokonca aj balík súkromné tie. Nič nebolo skutočne zapuzdrené, čo môže vývojárom knižníc spôsobiť všetky druhy problémov.

Pretože Java 9 presadzuje silné zapuzdrenie, teraz musíme výslovne udeliť povolenie iným modulom, aby odrážali naše triedy.

Ak chceme naďalej umožňovať úplnú reflexiu ako to robili staršie verzie Java, môžeme to jednoducho urobiť otvorené celý modul hore:

otvoriť modul my.module {}

4.9. Otvára sa

Ak potrebujeme povoliť odraz súkromných typov, ale nechceme, aby bol vystavený celý náš kód, môžeme použiť otvára smernice vystaviť konkrétne balíčky.

Pamätajte však, že to otvorí balík celému svetu, takže uistite sa, že to je to, čo chcete:

modul my.module {otvorí com.my.package; }

4.10. Otvára sa ... Komu

Dobre, takže reflexia je niekedy skvelá, ale stále chceme maximálnu bezpečnosť, z ktorej sa dá dostať zapuzdrenie. Môžeme selektívne otvoriť naše balíčky do vopred schváleného zoznamu modulov, v tomto prípade pomocou otvára ... do smernice:

modul my.module {otvorí com.my.package na moduleOne, moduleTwo atď .; }

5. Možnosti príkazového riadku

Doteraz bola do Maven a Gradle pridaná podpora pre moduly Java 9, takže nebudete musieť robiť veľa manuálnych stavieb svojich projektov. Stále je však cenné vedieť ako používať modulový systém z príkazového riadku.

Pre náš úplný príklad nižšie použijeme príkazový riadok, aby sme upevnili fungovanie celého systému v našich mysliach.

  • cesta moduluPoužívame –Modul-cesta možnosť určiť cestu k modulu. Toto je zoznam jedného alebo viacerých adresárov, ktoré obsahujú vaše moduly.
  • doplnkové čítania - Namiesto toho, aby sme sa spoliehali na deklaračný súbor modulu, môžeme použiť ekvivalent príkazového riadku k vyžaduje smernica; –Pridať-prečítať.
  • dodatočný vývozNáhrada príkazového riadku pre vývoz smernice.
  • doplnkové otváranieVymeňte otvorené doložka v súbore deklarácie modulu.
  • prídavné modulyPridá zoznam modulov do predvolenej sady modulov
  • zoznam-modulyVytlačí zoznam všetkých modulov a ich reťazcov verzií
  • patch modul - Pridajte alebo prepíšte triedy v moduloch
  • nelegálny prístup = povolenie | varovať | odmietnuť - Buď uvoľnite silné zapuzdrenie zobrazením jediného globálneho varovania, zobrazte každé varovanie alebo zlyhajte s chybami. Predvolená hodnota je povolenie.

6. Viditeľnosť

Mali by sme stráviť trochu času rozhovorom o viditeľnosti nášho kódu.

Mnoho knižníc závisí od reflexie, aby mohli svoje kúzlo uplatniť (Prichádza na rad JUnit a Spring).

V predvolenom nastavení v prostredí Java 9 budeme iba mať prístup k verejným triedam, metódam a poliam v našich exportovaných balíkoch. Aj keď používame reflexiu na získanie prístupu k neverejným členom a telefonovanie setAccessible (true), k týmto členom nebudeme mať prístup.

Môžeme použiť otvorené, otváraa otvára ... do možnosti na udelenie prístupu iba za behu na zamyslenie. Poznámka, toto je iba za behu!

Nebudeme môcť kompilovať proti súkromným typom a aj tak by sme to nikdy nemali potrebovať.

Ak musíme mať prístup k modulu na zamyslenie a nie sme vlastníkmi tohto modulu (t. J. Nemôžeme použiť otvára ... do smernica), potom je možné použiť príkazový riadok –Add-otvára možnosť povoliť vlastným modulom odrazový prístup k uzamknutému modulu za behu.

Jedinou výhradou je, že musíte mať prístup k argumentom príkazového riadku, ktoré sa používajú na spustenie modulu, aby to fungovalo.

7. Dáme všetko dohromady

Teraz, keď vieme, čo je modul a ako ich používať, poďme ďalej a vytvorme jednoduchý projekt na demonštráciu všetkých konceptov, ktoré sme sa práve naučili.

Aby to bolo jednoduché, nebudeme používať Maven ani Gradle. Namiesto toho sa pri zostavovaní našich modulov budeme spoliehať na nástroje príkazového riadku.

7.1. Pripravujeme náš projekt

Najskôr musíme nastaviť štruktúru nášho projektu. Vytvoríme niekoľko adresárov na usporiadanie súborov.

Začnite vytvorením priečinka projektu:

mkdir modul-projekt cd modul-projekt

Toto je základ celého nášho projektu, takže sem pridajte súbory, napríklad súbory na zostavenie Maven alebo Gradle, ďalšie zdrojové adresáre a zdroje.

Taktiež sme umiestnili adresár, kde sa nachádzajú všetky naše moduly špecifické pre projekt.

Ďalej vytvoríme adresár modulu:

jednoduché moduly mkdir

Takto bude vyzerať naša štruktúra projektu:

modul-projekt | - // src, ak použijeme predvolený balík | - // súbory na zostavenie tiež prejdú na túto úroveň | - jednoduché moduly | - hello.modules | - com | - baeldung | - moduly | - ahoj | - hlavný .app | - com | - baeldung | - moduly | - hlavné

7.2. Náš prvý modul

Teraz, keď máme zavedenú základnú štruktúru, pridajme náš prvý modul.

Pod jednoduché moduly adresár, vytvorte nový adresár s názvom ahoj.moduly.

Môžeme to pomenovať, čo len chceme, ale postupujte podľa pravidiel pre pomenovanie balíkov (t. j. bodky na oddelenie slov atď.). Ak chceme, môžeme ako názov modulu použiť aj názov nášho hlavného balíka, ale zvyčajne sa chceme držať rovnakého názvu, aký by sme použili na vytvorenie súboru JAR tohto modulu.

V rámci nášho nového modulu môžeme vytvárať požadované balíčky. V našom prípade vytvoríme jednu štruktúru balíka:

com.baeldung.modules.hello

Ďalej vytvorte novú triedu s názvom HelloModules.java v tomto balíku. Udržíme jednoduchý kód:

balík com.baeldung.modules.hello; verejná trieda HelloModules {public static void doSomething () {System.out.println ("Hello, Modules!"); }}

A nakoniec v ahoj.moduly koreňový adresár, pridajte náš deskriptor modulu; modul-info.java:

modul hello.modules {exporty com.baeldung.modules.hello; }

Aby tento príklad nebol jednoduchý, robíme iba export všetkých verejných členov com.baeldung.modules.hello balíček.

7.3. Náš druhý modul

Náš prvý modul je skvelý, ale nerobí nič.

Môžeme vytvoriť druhý modul, ktorý ho teraz používa.

Pod našou jednoduché moduly adresár, vytvorte ďalší adresár modulu s názvom main.app. Tentokrát začneme s deskriptorom modulu:

modul main.app {vyžaduje hello.modules; }

Nepotrebujeme nič vystavovať vonkajšiemu svetu. Namiesto toho všetko, čo musíme urobiť, je závisieť od nášho prvého modulu, takže máme prístup k verejným triedam, ktoré exportuje.

Teraz môžeme vytvoriť aplikáciu, ktorá ju používa.

Vytvorte novú štruktúru balíka: com.baeldung.modules.main.

Teraz vytvorte nový súbor triedy s názvom MainApp.java.

balíček com.baeldung.modules.main; import com.baeldung.modules.hello.HelloModules; public class MainApp {public static void main (String [] args) {HelloModules.doSomething (); }}

A to je všetok kód, ktorý potrebujeme na demonštráciu modulov. Naším ďalším krokom je zostavenie a spustenie tohto kódu z príkazového riadku.

7.4. Budovanie našich modulov

Na zostavenie nášho projektu môžeme vytvoriť jednoduchý bash skript a umiestniť ho do koreňového adresára nášho projektu.

Vytvorte súbor s názvom zostaviť- jednoduché- moduly.sh:

#! / usr / bin / env bash javac -d outDir --module-zdroj-cesta jednoduche-moduly $ (najdi jednoduche-moduly -name "* .java")

Tento príkaz má dve časti, javac a Nájsť príkazy.

The Nájsť príkaz jednoducho vypíše zoznam všetkých.java súbory v našom adresári jednoduchých modulov. Tento zoznam potom môžeme vložiť priamo do kompilátora Java.

Jediná vec, ktorú musíme urobiť inak ako staršie verzie Java, je poskytnúť a cesta-zdroja-modulu parameter informujúci kompilátor, že zostavuje moduly.

Po spustení tohto príkazu budeme mať znak outDir priečinok s dvoma zostavenými modulmi vo vnútri.

7.5. Spustenie nášho kódexu

A teraz môžeme konečne spustiť náš kód a overiť, či moduly fungujú správne.

Vytvorte ďalší súbor v koreňovom adresári projektu: run-simple-module-app.sh.

#! / usr / bin / env bash java --module-path outDir -m main.app/com.baeldung.modules.main.MainApp

Ak chcete spustiť modul, musíme poskytnúť aspoň: cesta modulu a hlavná trieda. Ak všetko funguje, mali by ste vidieť:

> $ ./run-simple-module-app.sh Dobrý deň, moduly!

7.6. Pridanie služby

Teraz, keď máme základné znalosti o tom, ako zostaviť modul, urobme to trochu komplikovanejším.

Uvidíme, ako sa bude používať poskytuje ... s a používa smernice.

Začnite definovaním nového súboru v priečinku ahoj.moduly pomenovaný modul HelloInterface.java:

verejné rozhranie HelloInterface {void sayHello (); }

Aby sme to uľahčili, implementujeme toto rozhranie do nášho existujúceho HelloModules.java trieda:

verejná trieda HelloModules implementuje HelloInterface {public static void doSomething () {System.out.println ("Hello, Modules!"); } public void sayHello () {System.out.println ("Dobrý deň!"); }}

To je všetko, čo musíme urobiť, aby sme vytvorili služby.

Teraz musíme svetu povedať, že náš modul poskytuje túto službu.

Pridajte k nášmu nasledujúce modul-info.java:

poskytuje com.baeldung.modules.hello.HelloInterface s com.baeldung.modules.hello.HelloModules;

Ako vidíme, deklarujeme rozhranie a ktorá trieda ho implementuje.

Ďalej to musíme skonzumovať služby. V našom main.app modulu, pridajme k nášmu nasledujúce modul-info.java:

používa com.baeldung.modules.hello.HelloInterface;

Nakoniec v našej hlavnej metóde môžeme túto službu použiť prostredníctvom ServiceLoader:

Iterovateľné služby = ServiceLoader.load (HelloInterface.class); Služba HelloInterface = services.iterator (). Next (); service.sayHello ();

Zostaviť a spustiť:

#> ./run-simple-module-app.sh Dobrý deň, moduly! Ahoj!

Tieto smernice používame na to, aby sme oveľa jasnejšie vysvetlili, ako sa má náš kód používať.

Implementáciu by sme mohli vložiť do súkromného balíka, zatiaľ čo by sme odhalili rozhranie vo verejnom balíku.

Vďaka tomu je náš kód oveľa bezpečnejší s veľmi malou réžiou navyše.

Pokračujte ďalej a vyskúšajte niektoré z ďalších smerníc, kde sa dozviete viac o moduloch a ich fungovaní.

8. Pridanie modulov do nepomenovaného modulu

Koncept nepomenovaného modulu je podobný predvolenému balíku. Preto sa nepovažuje za skutočný modul, ale dá sa považovať za predvolený modul.

Ak trieda nie je členom pomenovaného modulu, bude sa automaticky považovať za súčasť tohto nepomenovaného modulu.

Niekedy, aby sme v grafe modulov zaistili konkrétnu platformu, knižnicu alebo moduly poskytovateľa služieb, musíme pridať moduly do predvolenej koreňovej sady. Napríklad keď sa pokúsime spustiť programy Java 8 tak, ako sú, s kompilátorom Java 9, možno budeme musieť pridať moduly.

Všeobecne, možnosť pridať pomenované moduly do predvolenej sady koreňových modulov je –Pridat moduly (,)* kde je názov modulu.

Napríklad poskytnúť prístup všetkým java.xml.bind modulov by bola syntax:

--add-modules java.xml.bind

Aby sme to mohli použiť v Mavene, môžeme to isté vložiť do maven-compiler-plugin:

 org.apache.maven.plugins maven-compiler-plugin 3.8.0 9 9 --add-modules java.xml.bind 

9. Záver

V tejto rozsiahlej príručke sme sa zamerali a pokryli základy nového systému Java 9 Module.

Začali sme rozhovorom o tom, čo je modul.

Ďalej sme hovorili o tom, ako zistiť, ktoré moduly sú obsiahnuté v JDK.

Podrobne sme sa zaoberali aj súborom deklarácie modulu.

Teóriu sme zavŕšili rozhovorom o rôznych argumentoch príkazového riadku, ktoré budeme potrebovať na zostavenie našich modulov.

Nakoniec sme všetky naše doterajšie vedomosti uviedli do praxe a vytvorili jednoduchú aplikáciu postavenú na vrchole modulového systému.

Ak chcete vidieť tento kód a ešte viac, nezabudnite si ho pozrieť na Githube.


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