Útmutató a Java 9 modularitáshoz

1. Áttekintés

A Java 9 egy új absztrakciós szintet vezet be a csomagok felett, amelyet hivatalosan Java Platform Module System (JPMS) néven, röviden „Modulokként” neveznek.

Ebben az oktatóanyagban áttekintjük az új rendszert, és megvitatjuk annak különféle aspektusait.

Készítünk egy egyszerű projektet is, amely bemutatja az ebben az útmutatóban megtanulandó összes fogalmat.

2. Mi a modul?

Először is meg kell értenünk, mi is egy modul, mielőtt megértenénk, hogyan kell használni őket.

A modul a szorosan kapcsolódó csomagok és erőforrások csoportja, valamint egy új modulleíró fájl.

Más szóval, ez egy „Java Packages csomag” absztrakció, amely lehetővé teszi számunkra, hogy kódunkat még többször felhasználhatóvá tegyük.

2.1. Csomagok

A modul belsejében lévő csomagok megegyeznek azokkal a Java csomagokkal, amelyeket a Java kezdete óta használunk.

Amikor létrehozunk egy modult, a kódot belsőleg csomagokba rendezzük, ugyanúgy, mint korábban más projektekkel.

A kódunk rendezésén kívül csomagokat használunk annak meghatározására, hogy melyik kód nyilvánosan elérhető a modulon kívül. Több időt fogunk tölteni erről a cikk későbbi részében.

2.2. Erőforrások

Minden modul felelős az erőforrásaiért, mint például a média vagy a konfigurációs fájlok.

Korábban az összes erőforrást a projekt gyökérszintjére helyeztük, és kézzel kezeltük, hogy mely erőforrások tartoztak az alkalmazás különböző részeihez.

A modulokkal a szükséges képeket és XML fájlokat együtt szállíthatjuk azzal a modullal, amelyre szüksége van, így projektjeinket sokkal könnyebben kezelhetjük.

2.3. Modulleíró

Modul létrehozásakor tartalmazunk egy leíró fájlt, amely meghatározza az új modulunk több szempontját:

  • Név - modulunk neve
  • Függőségek - további modulok listája, amelyektől ez a modul függ
  • Nyilvános csomagok - a modulon kívülről elérhető összes csomag listája
  • Felajánlott szolgáltatások - olyan szolgáltatási megvalósításokat tudunk biztosítani, amelyeket más modulok is fel tudnak használni
  • Fogyasztott szolgáltatások - lehetővé teszi, hogy az aktuális modul egy szolgáltatás fogyasztója legyen
  • Reflekciós engedélyek - kifejezetten lehetővé teszi, hogy más osztályok reflektálást használhassanak a csomag privát tagjaihoz való hozzáféréshez

A modulok elnevezési szabályai hasonlóak a csomagok megnevezéséhez (pontok megengedettek, kötőjelek nem). Nagyon gyakran projekt stílusú (my.module) vagy Reverse-DNS (com.baeldung.mymodule) stílusnevek. Ebben az útmutatóban projektstílust fogunk használni.

Fel kell sorolnunk az összes csomagot, amelyik nyilvános akarunk lenni, mert alapértelmezés szerint az összes csomag privát modul.

Ugyanez vonatkozik a reflexióra is. Alapértelmezés szerint nem használhatjuk a reflexiót azokon az osztályokon, amelyeket egy másik modulból importálunk.

A cikk későbbiben megnézzük a modulleíró fájl használatának példáit.

2.4. Modultípusok

Az új modulrendszerben négyféle modul létezik:

  • Rendszer modulok- Ezek a modulok szerepelnek a futtatásakor lista-modulok parancsot fent. Ezek tartalmazzák a Java SE és a JDK modulokat.
  • Alkalmazási modulok - Ezeket a modulokat általában fel akarjuk építeni, amikor a modulok használata mellett döntünk. Az összeállításban megnevezik és meghatározzák őket module-info.class az összeállított JAR-ban található fájl.
  • Automatikus modulok - Nem hivatalos modulokat is felvehetünk úgy, hogy meglévő JAR fájlokat adunk a modul elérési útjához. A modul neve a JAR nevéből származik. Az automatikus modulok teljes olvasási hozzáféréssel rendelkeznek az útvonal által betöltött minden más modulhoz.
  • Névtelen modul - Ha egy osztály vagy JAR van betöltve az osztályútra, de a modul elérési útja nem, akkor az automatikusan hozzáadódik a meg nem nevezett modulhoz. Ez egy mindenre kiterjedő modul, amely fenntartja a visszafelé kompatibilitást a korábban írt Java-kóddal.

2.5. terjesztés

A modulok kétféleképpen oszthatók el: JAR fájlként vagy „felrobbant” összeállított projektként. Ez természetesen megegyezik bármely más Java-projekttel, így nem lehet meglepetés.

Hozhatunk létre több modulos projekteket, amelyek egy „fő alkalmazásból” és több könyvtári modulból állnak.

Vigyáznunk kell, mert JAR fájlonként csak egy modul lehet.

Amikor felépítjük a build fájlunkat, meg kell győződnünk arról, hogy a projektünk minden egyes modulját külön üvegként csomagoljuk-e.

3. Alapértelmezett modulok

A Java 9 telepítésekor láthatjuk, hogy a JDK most új struktúrával rendelkezik.

Elvették az összes eredeti csomagot és áthelyezték az új modulrendszerbe.

A parancssorba beírva láthatjuk, hogy mik ezek a modulok:

java --list-modulok

Ezek a modulok négy nagy csoportra oszthatók: java, javafx, jdk, és Jóslat.

Jáva a modulok az SE SE alapvető specifikációjának megvalósítási osztályai.

javafx modulok az FX UI könyvtárak.

Minden, ami magának a JDK-nak szükséges, a jdk modulok.

És végül, bármi, ami az Oracle-specifikus, az jóslat modulok.

4. Modulnyilatkozatok

A modul beállításához egy speciális fájlt kell elhelyeznünk a megnevezett csomagjaink gyökerében module-info.java.

Ez a fájl a modulleíró néven ismert, és tartalmazza az új modul felépítéséhez és használatához szükséges összes adatot.

A modult egy olyan deklarációval állítjuk össze, amelynek törzse üres vagy modul-irányelvekből áll:

modul myModuleName {// minden irányelv nem kötelező}

A modul deklarációt a modul kulcsszó, és ezt követjük a modul nevével.

A modul ezzel a nyilatkozattal működik, de általában több információra lesz szükségünk.

Itt jönnek be a modul irányelvek.

4.1. Igényel

Az első irányelvünk az igényel. Ez a modul irányelv lehetővé teszi számunkra a modulfüggőségek deklarálását:

modul my.module {megköveteli a modul.nevet; }

Most, my.module van futásidejű és fordítási időbeli függőség egyaránt tovább modul.név.

És minden függőségből exportált nyilvános típus elérhető modulunk által, amikor ezt az irányelvet használjuk.

4.2. Statikus

Néha olyan kódot írunk, amely hivatkozik egy másik modulra, de amelyet könyvtárunk felhasználói soha nem akarnak használni.

Például írhatunk egy segédfunkciót, amely szépen kinyomtatja a belső állapotunkat, amikor egy másik naplózási modul van jelen. De könyvtárunk nem minden fogyasztója akarja ezt a funkciót, és nem akar egy extra naplókönyvtárat is beépíteni.

Ezekben az esetekben egy opcionális függőséget szeretnénk használni. A statikus igényel irányelv alapján létrehozunk egy fordítási idő függőséget:

modul my.module {statikus modul.nevet igényel; }

4.3. Transitive-t igényel

Általában a könyvtárakkal dolgozunk, hogy megkönnyítsük az életünket.

De meg kell győződnünk arról, hogy bármelyik modul, amely behozza a kódunkat, behozza ezeket az extra „tranzitív” függőségeket, különben nem fognak működni.

Szerencsére használhatjuk a transzitív irányelv arra kényszeríti a későbbi fogyasztókat, hogy olvassák el a szükséges függőségeinket is:

modul my.module {tranzitív modul.nevet igényel; }

Most, amikor egy fejlesztő megköveteli a modulomat, nekik sem kell mondaniuk modul.nevet igényel hogy a modulunk továbbra is működjön.

4.4. Export

Alapértelmezés szerint egy modul egyetlen API-t sem tesz ki más modulok számára. Ez erős tokozás a modulrendszer létrehozásának egyik legfontosabb motiválója volt.

A kódunk lényegesen biztonságosabb, de most kifejezetten meg kell nyitnunk az API-t a világ előtt, ha azt akarjuk, hogy használható legyen.

Használjuk a export irányelv a megnevezett csomag összes nyilvános tagjának nyilvánosságra hozatalára:

modul a my.module {export com.my.package.name; }

Most, amikor valaki megteszi megköveteli a modulomat, hozzáférhetnek a mi nyilvános típusokhoz com.my.package.name csomagot, de más csomagot nem.

4.5. Export ... ide

Tudjuk használni export… ide hogy nyilvános osztályainkat megnyissuk a világ előtt.

De mi van, ha nem akarjuk, hogy az egész világ hozzáférjen az API-hoz?

A. Használatával korlátozhatjuk, hogy mely modulok férhetnek hozzá az API -inkhoz export… ide irányelv.

Hasonló a export irányelv szerint exportáltnak nyilvánítunk egy csomagot. De felsoroljuk azt is, hogy mely modulokat engedélyezzük a csomag importálásaként igényel. Lássuk, hogyan néz ki ez:

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

4.6. Használ

A szolgáltatás egy adott felület vagy elvont osztály megvalósítása, amely lehet elfogyasztott más osztályok által.

Kijelöljük azokat a szolgáltatásokat, amelyeket modulunk a használ irányelv.

Vegye figyelembe, hogy az osztály neve mi használat vagy a szolgáltatás interfésze vagy absztrakt osztálya, nem pedig a megvalósítási osztály:

modul my.module {class_name használja; }

Itt kell megjegyeznünk, hogy van különbség a igényel irányelv és a használ irányelv.

Mi talán megkövetelik egy modul, amely olyan szolgáltatást nyújt, amelyet el akarunk fogyasztani, de ez a szolgáltatás egy interfészt valósít meg egyik tranzitív függőségéből.

Ahelyett, hogy kényszerítenénk a modulunkat a követelményekre minden transzitív függőségeket csak arra az esetre használjuk használ irányelv a szükséges interfész hozzáadásához a modul elérési útjához.

4.7. Biztosítja…

Egy modul lehet a Szolgáltató hogy más modulok elfogyaszthatják.

Az irányelv első része a biztosítja kulcsszó. Ide tesszük a felületet vagy az absztrakt osztály nevét.

Ezután megvan a val vel irányelv, ahol megadjuk a megvalósítási osztály nevét megvalósítja az interfész vagy kiterjed az elvont osztály.

Így néz ki összerakva:

a my.module {modul biztosítja a MyInterface-t a MyInterfaceImpl-lel; }

4.8. Nyisd ki

Korábban említettük, hogy a kapszulázás ösztönözte a modulrendszer kialakítását.

A Java 9 előtt a reflexió segítségével megvizsgálhatta a csomag minden típusát és tagját, még a magán azok. Semmi sem volt igazán bezárva, ami mindenféle problémát felvethet a könyvtárak fejlesztői előtt.

Mivel a Java 9 érvényesíti erős tokozás, most kifejezetten engedélyt kell adnunk más moduloknak, hogy elmélkedhessenek az osztályainkon.

Ha továbbra is meg akarjuk engedni a teljes reflexiót, mint a Java régebbi verziói, egyszerűen megtehetjük nyisd ki a teljes modul fel:

nyissa meg a my.module modult {}

4.9. Megnyílik

Ha engedélyeznünk kell a privát típusok tükrözését, de nem akarjuk, hogy az összes kódunk látható legyen, használhatjuk a megnyílik irányelv bizonyos csomagok leleplezésére.

De ne feledje, hogy ez megnyitja a csomagot az egész világ számára, ezért győződjön meg róla, hogy ezt szeretné:

modul my.module {megnyitja a com.my.package; }

4.10. Megnyílik… Címzett

Oké, szóval a reflexió néha nagyszerű, de mégis minél nagyobb biztonságra vágyunk Egységbezárás. Szelektíven megnyithatjuk csomagjainkat egy előre jóváhagyott modullista számára, ebben az esetben a megnyílik… ide irányelv:

modul my.module {megnyitja a com.my.package-ot a moduleOne, moduleTwo stb .; }

5. Parancssori opciók

Mostanra a Java 9 modulok támogatása hozzáadódott a Mavenhez és a Gradle-hoz, így nem kell sok kézi projektet készíteni. Azonban még mindig értékes tudni hogyan hogy a modulrendszert a parancssorból használja.

Az alábbi teljes példához a parancssort fogjuk használni, hogy segítsünk megszilárdítani, hogy az egész rendszer hogyan működik elménkben.

  • module-pathHasználjuk a –Modul-út opció a modul elérési útjának megadásához. Ez egy vagy több könyvtárat tartalmaz, amelyek tartalmazzák a modulokat.
  • add-reads - Ahelyett, hogy a modul deklarációs fájljára támaszkodnánk, használhatjuk a parancssor megfelelőjét igényel irányelv; –Add-olvas.
  • add-exportParancssor cseréje a export irányelv.
  • bővítményekHelyettesíteni a nyisd ki záradék a modul deklarációs fájljában.
  • add-modulokHozzáadja a modulok listáját az alapértelmezett modulkészlethez
  • lista-modulokKinyomtatja az összes modul és azok verziósztringjeinek listáját
  • patch-module - Osztályok hozzáadása vagy felülírása egy modulban
  • illegális hozzáférés = engedély | figyelmeztet | megtagad - Vagy enyhítse az erős beágyazást egyetlen globális figyelmeztetés megjelenítésével, minden figyelmeztetést mutasson, vagy hibával kudarcot valljon. Az alapértelmezett engedély.

6. Láthatóság

El kellene töltenünk egy kis időt a kódunk láthatóságáról.

Nagyon sok könyvtár a reflexiótól függ, hogy varázslatos legyen (JUnit és Tavasz jut eszembe).

Alapértelmezés szerint a Java 9-ben megtesszük csak hozzáférhetnek az exportált csomagjaink nyilvános osztályaihoz, módszereihez és mezõihez. Még akkor is, ha a reflexió segítségével hozzáférünk a nem nyilvános tagokhoz és hívunk setAccessible (true), nem fogjuk tudni elérni ezeket a tagokat.

Használhatjuk a nyisd ki, megnyílik, és megnyílik… ide lehetőségek csak futásidejű hozzáférés biztosítására a reflexióhoz. Jegyzet, ez csak futásidejű!

Nem tudunk magántípusokról összeállítani, és amúgy sem kellene.

Ha reflexióhoz hozzáférnünk kell egy modulhoz, és nem mi vagyunk a modul tulajdonosa (vagyis nem használhatjuk a modult megnyílik… ide irányelv), akkor lehetséges a parancssor használata –Add-nyit opció, amely lehetővé teszi a saját modulok reflexiós hozzáférését a lezárt modulhoz futás közben.

Az egyetlen figyelmeztetés, hogy hozzáférnie kell azokhoz a parancssori argumentumokhoz, amelyeket egy modul futtatásához használnak, hogy ez működjön.

7. Összedobni az egészet

Most, hogy tudjuk, mi a modul, és hogyan kell használni őket, menjünk tovább, és készítsünk egy egyszerű projektet az imént tanult fogalmak bemutatására.

A dolgok egyszerűbbé tétele érdekében nem Mavenet vagy Gradle-t fogunk használni. Ehelyett a parancssori eszközökre támaszkodunk moduljaink felépítéséhez.

7.1. Projektünk beállítása

Először fel kell állítanunk a projekt felépítését. Több könyvtárat hozunk létre a fájljaink rendezéséhez.

Először hozza létre a projekt mappát:

mkdir modul-projekt cd modul-projekt

Ez az egész projektünk alapja, ezért adjon ide fájlokat, például Maven vagy Gradle build fájlokat, más forráskönyvtárakat és erőforrásokat.

Feltettünk egy könyvtárat is, amely az összes projekt-specifikus modulunkat tartalmazza.

Ezután létrehozunk egy modul könyvtárat:

mkdir egyszerű modulok

Így fog kinézni a projekt felépítése:

module-project | - // src, ha az alapértelmezett csomagot használjuk | - // a build fájlok szintén ezen a szinten mennek | .app | - com | - baeldung | - modulok | - main

7.2. Első modulunk

Most, hogy az alapstruktúra a helyén van, tegyük hozzá az első modulunkat.

Alatt egyszerű modulok könyvtárat, hozzon létre egy új könyvtárat szia.modulok.

Bármit megnevezhetünk, amit csak akarunk, de betartjuk a csomagnévadási szabályokat (azaz periódusok a szavak elkülönítésére stb.). Akár a fő csomagunk nevét is használhatjuk a modul neveként, ha akarjuk, de általában ugyanarra a névre szeretnénk ragaszkodni, amelyet a modul JAR-jának létrehozásához használnánk.

Új modulunk alatt létrehozhatjuk a kívánt csomagokat. Esetünkben egy csomagstruktúrát fogunk létrehozni:

com.baeldung.modules.hello

Ezután hozzon létre egy új osztályt HelloModules.java ebben a csomagban. A kódot egyszerűvé fogjuk tenni:

csomag com.baeldung.modules.hello; public class HelloModules {public static void doSomething () {System.out.println ("Hello, modulok!"); }}

És végül a szia.modulok gyökérkönyvtár, adja hozzá a modul leírójához; module-info.java:

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

Annak érdekében, hogy ez a példa egyszerű legyen, csak annyit teszünk, hogy a com.baeldung.modules.hello csomag.

7.3. Második modulunk

Az első modulunk remek, de nem csinál semmit.

Hozhatunk létre egy második modult, amely most használja.

A mi alattunk egyszerű modulok könyvtárat, hozzon létre egy másik modul könyvtárat main.app. Ezúttal a modulleíróval kezdjük:

modul main.app {hello.modules szükséges; }

Nem kell semmit kitenni a külvilág elé. Ehelyett csak annyit kell tennünk, hogy az első modulunkon múlik, így hozzáférünk az általa exportált nyilvános osztályokhoz.

Most létrehozhatunk egy alkalmazást, amely használja.

Hozzon létre egy új csomagstruktúrát: com.baeldung.modules.main.

Most hozzon létre egy új osztályfájlt MainApp.java.

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

És ez az összes kód, amelyre szükségünk van a modulok bemutatásához. A következő lépésünk a kód felépítése és futtatása a parancssorból.

7.4. Moduljaink építése

A projektünk elkészítéséhez létrehozhatunk egy egyszerű bash szkriptet, és elhelyezhetjük a projekt gyökerében.

Hozzon létre egy nevű fájlt compile-simple-modules.sh:

#! / usr / bin / env bash javac -d outDir --module-source-path simple-modules $ (find simple-modules -name "* .java")

Ennek a parancsnak két része van, a javac és megtalálja parancsokat.

A megtalálja parancs egyszerűen kiadja az összes listáját.Jáva fájlokat az egyszerű modulok könyvtárunk alatt. Ezután betáplálhatjuk ezt a listát közvetlenül a Java fordítóba.

Az egyetlen dolog, amit másképp kell tennünk, mint a Java régebbi verziói, az a module-source-path paraméter a fordító tájékoztatására, hogy modulokat épít.

Miután futtattuk ezt a parancsot, lesz egy outDir mappa két lefordított modullal.

7.5. Kódunk futtatása

És most végre futtathatjuk kódunkat annak ellenőrzésére, hogy a modulok megfelelően működnek-e.

Hozzon létre egy másik fájlt a projekt gyökérkönyvtárában: run-simple-module-app.sh.

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

A modul futtatásához meg kell adnunk legalább a module-path és a főosztály. Ha minden működik, akkor látnia kell:

> $ ./run-simple-module-app.sh Helló, modulok!

7.6. Szolgáltatás hozzáadása

Most, hogy alapvető ismereteink vannak a modul felépítéséről, tegyük egy kicsit bonyolultabbá.

Meg fogjuk nézni, hogyan kell használni a biztosítja… és használ irányelvek.

Kezdje azzal, hogy definiál egy új fájlt a szia.modulok nevű modul HelloInterface.Jáva:

nyilvános felület HelloInterface {void sayHello (); }

A dolgok megkönnyítése érdekében ezt a felületet a meglévő rendszerünkkel fogjuk megvalósítani HelloModules.java osztály:

public class HelloModules implementálja a HelloInterface {public static void doSomething () {System.out.println ("Hello, modulok!"); } public void sayHello () {System.out.println ("Hello!"); }}

Ennyit kell tennünk a szolgáltatás.

Most el kell mondanunk a világnak, hogy modulunk biztosítja ezt a szolgáltatást.

Adja hozzá a következőket a mi module-info.java:

a com.baeldung.modules.hello.HelloInterface szolgáltatást a com.baeldung.modules.hello.HelloModules;

Mint láthatjuk, deklaráljuk az interfészt és azt, hogy melyik osztály valósítja meg.

Ezután ezt kell fogyasztanunk szolgáltatás. Miénkben main.app modulhoz tegyük hozzá a következőket module-info.java:

com.baeldung.modules.hello.HelloInterface;

Végül a fő módszerünkben ezt a szolgáltatást egy ServiceLoaderen keresztül használhatjuk:

Iterálható szolgáltatások = ServiceLoader.load (HelloInterface.class); HelloInterface szolgáltatás = services.iterator (). Next (); service.sayHello ();

Összeállítás és futtatás:

#> ./run-simple-module-app.sh Helló, modulok! Helló!

Ezeket az irányelveket arra használjuk, hogy sokkal világosabbá tegyük a kódunk használatát.

Helyezhetjük a megvalósítást egy privát csomagba, miközben a felületet egy nyilvános csomagban tesszük közzé.

Ez sokkal biztonságosabbá teszi kódunkat, nagyon kevés extra rezsivel.

Menjen tovább, és próbáljon ki néhány más irányelvet, hogy többet tudjon meg a modulokról és azok működéséről.

8. Modulok hozzáadása a Névtelen modulhoz

A meg nem nevezett modul koncepció hasonló az alapértelmezett csomaghoz. Ezért nem tekinthető valós modulnak, de alapértelmezettként tekinthető meg.

Ha egy osztály nem tagja egy megnevezett modulnak, akkor automatikusan ennek a meg nem nevezett modulnak számít.

Előfordulhat, hogy bizonyos platform, könyvtár vagy szolgáltató modulok biztosításához a moduldiagramon meg kell adnunk modulokat az alapértelmezett gyökérkészlethez. Például, amikor megpróbálunk Java 8 programokat futtatni a Java 9 fordítóval úgy, ahogy van, akkor szükség lehet modulok hozzáadására.

Általánosságban, a megnevezett modulok hozzáadása az alapértelmezett gyökérmodulokhoz az –Add-modulok (,)* hol egy modul neve.

Például hozzáférés biztosítása mindenki számára java.xml.bind modulok szintaxisa a következő lenne:

--add-modules java.xml.bind

Ennek a Mavenben való használatához beágyazhatjuk ugyanezt a maven-compiler-plugin:

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

9. Következtetés

Ebben a kiterjedt útmutatóban az új Java 9 modul rendszer alapjaira összpontosítottunk és áttekintettük őket.

Először arról beszéltünk, hogy mi is a modul.

Ezután arról beszéltünk, hogyan lehet felfedezni, hogy mely modulok szerepelnek a JDK-ban.

Részletesen kitértünk a modul deklarációs fájljára is.

Az elméletet úgy egészítettük ki, hogy beszélgettünk a különféle parancssori argumentumokról, amelyekre szükségünk lesz moduljaink felépítéséhez.

Végül minden eddigi tudásunkat átültettük a gyakorlatba, és létrehoztunk egy egyszerű alkalmazást, amely a modulrendszer tetejére épült.

Ha látni szeretné ezt a kódot és még sok mást, ellenőrizze a Githubon.