Bevezetés a Jigsaw projektbe
1. Bemutatkozás
A Project Jigsaw egy olyan esernyőprojekt, amely két új szempontot tartalmaz:
- modulrendszer bevezetése Java nyelven
- és megvalósítása a JDK forrás- és Java futásidejében
Ebben a cikkben bemutatjuk a Jigsaw projektet és annak jellemzőit, majd egy egyszerű moduláris alkalmazással összefoglaljuk.
2. Modularitás
Egyszerűen fogalmazva, a modularitás olyan tervezési elv, amely segít elérni:
- laza csatlakozás az alkatrészek között
- egyértelmű szerződések és az összetevők közötti függőségek
- rejtett megvalósítás erős kapszulázással
2.1. Modularitás mértékegysége
Most jön a kérdés, hogy mi a modularitás egysége? A Java világban, különösen az OSGi esetében, a JAR-okat tekintették a modularitás egységének.
A JAR-ok segítettek a kapcsolódó összetevők csoportosításában, de vannak bizonyos korlátozásaik:
- kifejezett szerződések és függőségek a JAR-ok között
- az elemek gyenge beágyazása a JAR-okba
2.2. JAR Hell
Volt egy másik probléma a JAR-okkal - a JAR pokol. Az osztályúton fekvő JAR-ok több változata eredményezte a ClassLoader az első megtalált osztály betöltése a JAR-ból, nagyon váratlan eredménnyel.
A classpath-t használó JVM másik problémája az volt, hogy az alkalmazás összeállítása sikeres lesz, de az alkalmazás futás közben nem fog sikerülni a ClassNotFoundException, futás közben az osztálypályán hiányzó JAR-ok miatt.
2.3. A modularitás új egysége
Mindezen korlátozások mellett, amikor a JAR-ot használják a modularitás egységeként, a Java nyelv készítői új konstrukcióval álltak elő a moduloknak nevezett nyelven. És ezzel egy teljesen új moduláris rendszert terveznek a Java számára.
3. Projekt Jigsaw
A projekt elsődleges motivációi a következők:
- hozzon létre egy modulrendszert a nyelv számára - a JEP 261. alatt hajtják végre
- alkalmazza a JDK forrásra - a JEP 201 keretében hajtják végre
- modulálja a JDK-tkönyvtárak - a JEP 200 keretében hajtják végre
- frissítse a futási időt a modularitás támogatására - a JEP 220 keretében hajtják végre
- tudjon kisebb futási időt létrehozni a JDK moduljainak részhalmazával - a JEP 282. alatt hajtják végre
Egy másik fontos kezdeményezés a belső API-k beágyazása a JDK-ba, azok, akik az nap.* csomagok és más nem szabványos API-k. Ezeket az API-kat soha nem akarták a nyilvánosság számára használni, és soha nem tervezték, hogy fenntartsák őket. De ezeknek az API-knak az ereje arra késztette a Java fejlesztőket, hogy felhasználják őket a különböző könyvtárak, keretrendszerek és eszközök fejlesztésében. Néhány belső API-hoz cserét biztosítottak, a többit pedig belső modulokba helyezték át.
4. Új eszközök a modularitáshoz
- jdeps - segít a kódbázis elemzésében a JDK API-k és a harmadik fél JAR-októl való függőségek azonosításában. Megemlíti annak a modulnak a nevét is, ahol a JDK API megtalálható. Ez megkönnyíti a kódalap modulizálását
- jdeprscan - segít elemezni az elavult API-k használatának kódbázisát
- jlink - az alkalmazás és a JDK moduljainak kombinálásával segít egy kisebb futási idő létrehozásában
- jmod - segít a jmod fájlokkal való munkában. A jmod egy új formátum a modulok csomagolásához. Ez a formátum lehetővé teszi natív kód, konfigurációs fájlok és egyéb adatok beillesztését, amelyek nem illenek a JAR fájlokba
5. Modul Rendszerarchitektúra
A nyelvben megvalósított modulrendszer ezeket a csomagokhoz hasonlóan legfelső szintű konstrukcióként támogatja. A fejlesztők modulokba rendezhetik kódjukat, és a moduldefiníciós fájljaikban deklarálhatják közöttük a függőségeket.
Egy moduldefiníciós fájl, amelynek neve: module-info.java, a következőket tartalmazza:
- annak a neve
- az általa nyilvánosan hozzáférhetővé tett csomagokat
- a modulok, melyektől függ
- bármely általa igénybe vett szolgáltatás
- az általa nyújtott szolgáltatás bármilyen megvalósítása
A fenti lista utolsó két elemét nem szokták használni. Ezeket csak akkor használják, ha a szolgáltatásokat a java.util.ServiceLoader felület.
A modul általános felépítése a következőképpen néz ki:
src | ---- com.baeldung.reader | | ---- module-info.java | | ---- com | | ---- baeldung | | ---- olvasó | | ---- Test.java | ---- com.baeldung.writer | ---- module-info.java | ---- com | ---- baeldung | ---- író | --- -Egy másik teszt.java
A fenti ábra két modult határoz meg: com.baeldung.reader és com.baeldung.writer. Mindegyiküknek meg van adva a definíciója module-info.java alatt elhelyezett kódfájlokat com / baeldung / reader és com / baeldung / íróill.
5.1. Modul Definíció Terminológiák
Nézzünk meg néhány terminológiát; a modul definiálása során fogjuk használni (vagyis a module-info.java):
- modul: a moduldefiníciós fájl ezzel a kulcsszóval kezdődik, amelyet a neve és a definíció követ
- igényel: a függő modulok jelzésére szolgál; e kulcsszó után meg kell adni a modul nevét
- tranzitív: a igényel kulcsszó; ez azt jelenti, hogy bármely modul, amely a modul meghatározásától függ transzitív implicit függést kap a <-tólmodulnév>
- export: a nyilvánosan elérhető modulban lévő csomagok megjelölésére szolgál; e kulcsszó után meg kell adni a csomag nevét
- megnyílik: a csak futás közben elérhető és a Reflection API-n keresztül introspekcióra is elérhető csomagok megjelölésére szolgál; ez meglehetősen jelentős az olyan könyvtárak számára, mint a Spring és a Hibernate, amelyek nagymértékben támaszkodnak a Reflection API-kre; megnyílik modul szinten is használható, ebben az esetben a teljes modul futás közben elérhető
- használ: a modul által használt szolgáltatási interfész jelzésére szolgál; egy típusnevet, azaz a teljes osztály / interfész nevet kell megadni a kulcsszó után
- biztosítja….: arra használják, hogy jelezzék, hogy a val vel kulcsszó, a biztosítja kulcsszó
6. Egyszerű moduláris alkalmazás
Hozzunk létre egy egyszerű moduláris alkalmazást modulokkal és azok függőségeivel, az alábbi ábra szerint:
A com.baeldung.student.model a root modul. Meghatározza a modellosztályt com.baeldung.student.model.Student, amely a következő tulajdonságokat tartalmazza:
public class Student {private String registrationId; // egyéb releváns mezők, getterek és beállítók}
Más modulokat biztosít a programban meghatározott típusokkal com.baeldung.student.model csomag. Ezt úgy érjük el, hogy meghatározzuk a fájlban module-info.java:
modul com.baeldung.student.model {export com.baeldung.student.model; }
A com.baeldung.student.service modul interfészt biztosít com.baeldung.student.service.StudentService absztrakt CRUD műveletekkel:
nyilvános felület StudentService {public String create (hallgató hallgató); public Student read (String registrationId); nyilvános hallgatói frissítés (hallgatói hallgató); nyilvános karakterlánc törlése (String registrationId); }
Attól függ com.baeldung.student.model modul, és elkészíti a csomagban definiált típusokat com.baeldung.student.service elérhető más modulokhoz:
modul com.baeldung.student.service {transzitív com.baeldung.student.model szükséges; exportálja a com.baeldung.student.service szolgáltatást; }
További modult biztosítunk com.baeldung.student.service.dbimpl, amely biztosítja a megvalósítást com.baeldung.student.service.dbimpl.StudentDbService a fenti modulhoz:
public class A StudentDbService megvalósítja a StudentService {public String create (Student student) {// Student létrehozása a DB-ben return student.getRegistrationId (); } public Student read (String registrationId) {// Diák olvasása a DB-ből return new Student (); } public Student update (Student student) {// Diák frissítése a DB visszatérő hallgatóban; } public String delete (String registrationId) {// Tanuló törlése a DB return registrationId-ben; }}
Közvetlenül attól függ com.baeldung.student.service és átmenetileg tovább com.baeldung.student.model és meghatározása a következő lesz:
modul com.baeldung.student.service.dbimpl {transzitív com.baeldung.student.service szükséges; java.logginget igényel; exportálja a com.baeldung.student.service.dbimpl; }
Az utolsó modul egy kliens modul - amely a szolgáltatás megvalósítási modult használja com.baeldung.student.service.dbimpl műveleteinek elvégzéséhez:
public class StudentClient {public static void main (String [] args) {StudentService service = new StudentDbService (); service.create (új Student ()); service.read ("17SS0001"); service.update (új Student ()); service.delete ("17SS0001"); }}
És meghatározása:
modul com.baeldung.student.client {szükséges com.baeldung.student.service.dbimpl; }
7. A minta összeállítása és futtatása
A fenti modulok fordításához és futtatásához szkripteket biztosítottunk a Windows és a Unix platformokhoz. Ezek megtalálhatók a core-java-9 projekt itt. A Windows platform végrehajtásának sorrendje:
- összeállítás-hallgató-modell
- összeállítás-hallgató-szolgáltatás
- compile-student-service-dbimpl
- összeállítás-hallgató-kliens
- run-student-client
A Linux platform végrehajtásának sorrendje meglehetősen egyszerű:
- fordító modulok
- run-student-client
A fenti szkriptekben a következő két parancssori argumentumot ismertetjük:
- –Modul-forrás-útvonal
- –Modul-út
A Java 9 felszámolja az osztályút fogalmát, és bevezeti a modul elérési útját. Ez az útvonal az a hely, ahol a modulok felfedezhetők.
Ezt a parancssori argumentummal állíthatjuk be: –Modul-út.
Több modul egyszerre történő fordításához használjuk a –Modul-forrás-útvonal. Ez az argumentum a modul forráskódjának megadására szolgál.
8. A JDK Forrásra alkalmazott modulrendszer
Minden JDK telepítéshez tartozik a src.zip. Ez az archívum tartalmazza a JDK Java API-k kódbázisát. Ha kibontja az archívumot, több mappát talál, néhány kezdőbetűvel Jáva, kevesen vannak javafx a többit pedig jdk. Minden mappa egy modult jelent.
A kezdő modulok Jáva a JDK modulok, amelyek a következőkkel kezdődnek javafx a JavaFX modulok és mások kezdődnek jdk a JDK eszközök moduljai.
Az összes JDK modul és az összes felhasználó által definiált modul implicit módon függ a java.base modul. A java.base modul tartalmaz olyan általánosan használt JDK API-kat, mint például az Utils, Collections, IO, Concurrency. A JDK modulok függőségi grafikonja:
Megtekintheti a JDK modulok definícióit is, hogy képet kapjon a szintaxisról a module-info.java.
9. Következtetés
Ebben a cikkben egy egyszerű moduláris alkalmazás létrehozását, fordítását és futtatását vizsgáltuk. Láttuk azt is, hogy miként modulálták a JDK forráskódját.
Kevés izgalmasabb funkció létezik, például kisebb futási idő létrehozása a linker eszköz - jlink használatával és moduláris üvegek létrehozása a többi funkció mellett. Ezeket a funkciókat a későbbi cikkekben részletesen bemutatjuk.
A Jigsaw projekt hatalmas változás, és várnunk kell, és meg kell néznünk, hogyan fogadja el a fejlesztői ökoszisztéma, különösen az eszközökkel és a könyvtár készítőivel.
A cikkben használt kód megtalálható a GitHub oldalon.