Primii pași cu java 9 și proiectul jigsaw sunt partea a doua

  • 11.12.15 07:47
  • ph_piter •
  • # 272861
  • Habrahabr •
  • Traducere •
  • 7 •
  • 8800

- la fel ca Forbes, doar mai bine.

După o anumită întârziere, publicăm a doua parte a articolului despre proiectul Jigsaw și Java 9, publicat pe blogul Codecentric. Traducerea primei părți este aici.

Aceasta este a doua parte a articolului pentru cei care doresc să se familiarizeze mai mult cu proiectul Jigsaw. În prima parte, am discutat pe scurt ce este un modul și cum a fost modularizat runtime-ul Java Runtime. Apoi am analizat un exemplu simplu de compilare, ambalare și rulare a unei aplicații modulare.

Aici vom încerca să răspundem la următoarele întrebări:

Să luăm ca exemplu exemplul din partea 1 și să continuăm să lucrăm cu acesta. Codul este încă aici.

Acordarea dreptului de a citi module specifice

Astfel, numai controlorul de adrese poate accesa API-ul zipvalidator. Această instrucțiune este executată la nivelul pachetului, astfel încât nimic nu vă împiedică să restricționați accesul pentru anumite pachete, oferind în același timp acces complet pentru alții. Această practică se numește "export calificat". Dacă modulul de.codecentric.nastymodule încearcă să acceseze orice tip de la de.codecentric.zipvalidator.api. atunci va exista o eroare de compilare:


Notă: programul nu jură pe module-info.java. deoarece zipvalidatorul ar putea, în principiu, să exporte pachetele vizibile la nastymodule. De exemplu, exportul calificat poate fi aplicat atunci când doriți să modificați structura internă a aplicației dvs., dar nu doriți să partajați pachetele exportate de module interne cu clienții.

Conflicte între versiunile modulului

Se întâmplă deseori că, prin dependențele tranzitorii, diferite versiuni ale bibliotecii intră în aceeași aplicație - adică același modul poate apărea de două ori pe calea către module. Două scenarii vin imediat în minte:

  • Modulele sunt disponibile la compilarea timpului în diferite directoare sau borcane modulare, dar au același nume la fel
  • Versiuni diferite ale aceluiași modul sunt de diferite nume

Să încercăm să compilam aplicația în primul scenariu. Zipvalidatorul a fost copiat:


Modulele duplicate sunt în directoare diferite, dar numele modulului rămâne neschimbat. Cum răspunde Jigsaw la acest lucru în timpul compilării?

Deci, aici suntem ușor să nu scăpăm. Jigsaw emite o eroare de compilare atunci când există două module cu același nume în calea spre module.

Cum rămâne cu al doilea caz? Structura director rămâne aceeași, dar acum ambele zipvalidator'a primesc diferite denumiri (de.codecentric.zipvalidator.v), și addresschecker citesc ambele nume.

Dezvoltatorul va ignora cu ușurință un astfel de avertisment și va lansa aplicația. Dar, evident, Jigsaw nu-i place ceea ce vede în timpul runtime-ului:

Mi se pare incomprehensibil, în opinia mea, eroarea de compilare a timpului ar putea fi aranjată și mai atentă. Am întrebat lista de discuții. de ce această opțiune a fost aleasă, dar la momentul redactării articolului nu a primit încă un răspuns.

Module automate și modul anonim

Până acum, am lucrat într-un mediu complet modularizat. Dar ce să faci în astfel de cazuri foarte probabile atunci când trebuie să te ocupi de fișierele Jar-modulare? Aici se pun în joc module automate și un modul anonim.

Să începem cu module automate. Modulul automat este un fișier de borcan livrat în modullepath. După ce scrieți-o acolo, veți putea răspunde la următoarele trei întrebări despre acest modul:

Î: Care este numele lui?
R: Acesta este numele fișierului jar. Dacă puneți fișierul guava.jar în calea către module, veți primi un modul automat de guava.

Acest lucru înseamnă, de asemenea, că nu puteți utiliza Jar direct din depozitul Maven, deoarece guava-18.0 nu este un identificator Java valid.

Î: Ce export?
R: Modulul automat exportă toate pachetele sale. Astfel, toate tipurile publice vor fi disponibile pentru orice modul care citește modulul automat.

Să luăm în considerare un exemplu. Începem să folosim com.google.common.base.Strings în zipvalidator. Pentru a permite acest acces, trebuie să definim marginea citită pentru modulul Guava automat:

Pentru a compila, trebuie să specificați fișierul guava.jar în calea către module (este în directorul / jars):


Totul este perfect compilat și lansat.

(De altfel, nu a fost atât de ușor pentru a rula acest exemplu de a lucra cu ansamblul de Jigsaw 86, am fugit în unele probleme :. Sistem jurat despre dependențele jdk.management.resource modulul am întrebat-o în buletinul informativ, discuția poate fi găsit aici ..

Trebuie să spun că, în decizia mea, nu am folosit construirea "timpurie" (construirea accesului timpuriu), dar am colectat eu singur JDK. Când lucram cu OSX Mavericks, au existat încă unele probleme, așa cum a fost scris în firul, trebuia să schimb fișierul de makefile, dar în cele din urmă am făcut totul. Poate că veți întâlni alte probleme atunci când lucrați cu următoarele versiuni).

Acum este momentul să vă prezentăm ajutorul de mână, care este indispensabil în tranziția spre Jigsaw. Acest instrument este numit "hoops". Se uită prin codul dvs. nemodulat și vă spune despre dependențe.

- /jars/guava.jar
Avem următoarea concluzie:
guava.jar -> java.base
guava.jar -> java.logging
guava.jar -> nu a fost găsit

Aceasta înseamnă că modulul automat de guava necesită java.base. java.logging și ... "nu a fost găsit". Ce este? Dacă eliminați comutatorul -s. apoi golesc părăsește nivelul modulului și coboară un pas spre nivelul pachetului (lista este ușor scurtată, deoarece există destul de puține pachete de guava):

Aceasta arată că pachetul com.google.common.xml depinde de com.google.common.escape. care este localizat în modulul propriu-zis, java.lang. care este bine cunoscut, și din adnotarea javax.notnotation. care nu se găsește. Am tras concluzia că avem nevoie de un borcan cu tipurile de JSR-305, deoarece conține javax.annotation (de altfel, am obține în jur fără ele - în exemplele mele, nu am nevoie de nici un fel de aceste pachete, și nici compilatorul sau runtime nu este obiect).

Deci, ce este un modul fără nume? Din nou, răspundem la trei întrebări:

Î: Care este numele lui?
R: După cum ați ghicit deja, el nu are un nume

Î: Ce cere?
R: Modulul fără nume citește toate celelalte module disponibile.

Deci, dacă nu puteți citi un modul anonim din oricare dintre modulele dvs., care este scopul? Prietenul nostru vechi ne ajută să răspundem la această întrebare - calea spre cursuri. Orice tip citit din classpath (și nu din drum modulelor) este plasat automat în modulul de inel - sau, cu alte cuvinte, orice tip de modul este încărcat în inelul prin classpath. Deoarece modulul anonim citește toate celelalte module, putem accesa toate tipurile exportate din orice tip încărcat prin clasă. În Java 9, utilizarea căii către clase și calea către module vor fi acceptate atât separat, cât și împreună, pentru a asigura compatibilitatea înapoi. Să luăm în considerare câteva exemple.

Să presupunem că avem un modul zipvalidator elegant, dar verificatorul de adrese nu este încă modularizat, nu are module-info.java. Structura surselor noastre va fi:

Acum, există un catalog al classpath, care conține codul de moștenire, legat de accesul la zipvalidator, și directorul modulepath care conține modulul zipvalidator. Ne putem compila modulele ca de obicei. Pentru a compila codul moștenit, trebuie să furnizăm informații despre codul modular. Doar scrie-o în modul de cursuri:


Totul funcționează ca de obicei.

În timpul performanței avem două posibilități. Și anume:
  • Scrieți modulul în calea de clasă
  • Mixați calea către clase și calea către module

Alegerea primei opțiuni, noi, de fapt, abandonăm sistemul modular. Toate tipurile pe care le scriem în modulul fără nume vor putea să se acceseze reciproc în mod liber.

funcționează la fel ca aplicația java pe care o utilizați astăzi.

Pe de altă parte, folosirea mixtă a căii spre module și a drumului spre clase funcționează astfel:

Utilizăm două comutatoare în același timp: -classpath și -modulepath. -addmods Adăugat comutator - când classpath amestecat și calea către modulele, nu putem obține doar acces la orice modul în directoarele modulepath și trebuie să precizeze care dintre ele ar trebui să fie disponibile.

Această abordare funcționează bine, dar aici este o captură! Rețineți că răspunsul la întrebarea "ce cere un modul fără nume" este "toate celelalte module". Dacă folosim modulul zipvalidator prin modullepath, putem lucra numai cu pachetele exportate. Totul va duce la IllegalAccessError în timpul rulării. Prin urmare, în acest caz, va trebui să urmați regulile sistemului de module.

Crearea imaginilor runtime folosind jlink

Exemple suficiente cu module; a existat încă un instrument nou, care merită atenția noastră. jlink este un utilitar Java 9 pentru crearea propriilor distribuții JVM. Cel mai interesant este că, datorită noii arhitecturi modulare a JDK, puteți alege modulele pe care doriți să le includeți în acest kit de distribuție! Să luăm în considerare un exemplu. Dacă vrem să creăm o imagine a runtime-ului care să conțină addresschecker-ul nostru, atunci dăm comanda:


Indicăm doar trei lucruri:

  • Calea către module (inclusiv modulele noastre speciale și calea spre directorul jmods din JDK - aici sunt modulele java standard)
  • Module pe care doriți să le includeți în distribuția dvs.
  • Director de rezultate

Comanda creează următoarea structură:

linkedjdk /
+-- bin
| + - java
| L - instrument de tastatură
+-- conf
| + - net.properties
| L - securitate
| + - java.policy
| L-- java.security
L-- lib
+-- classlist
+-- JLI


Asta e tot. În Mavericks OSX, totul durează aproximativ 47 MB. De asemenea, putem folosi arhivarea și eliminăm câteva funcții de depanare pe care încă nu aveți nevoie să le creați în producție. Cea mai compactă distribuție, pe care am reușit să o creez, a fost obținută cu ajutorul acestei comenzi:

Dimensiunea distribuției este redusă la aproximativ 18 MB, în opinia mea - doar superbă. În Linux, probabil, puteți ascunde până la 13.

Listează modulele din această distribuție

Deci, toate aplicațiile care depind de numărul maxim de module pot funcționa pe acest JVM. Dar nu am reușit să primesc clasa noastră principală pentru a rula acest scenariu. Pentru asta am mers invers.

Cititorul atent a putut observa că cel de-al doilea apel este făcut la jlink, iar calea spre module este diferită acolo decât la primul apel. În cel de-al doilea caz, specificăm calea spre directorul bin. Acest director conține fișiere jar-modulare, iar jar-ul pentru addresschecker conține, de asemenea, informații despre clasa principală din manifestul său. Utilitarul jlink utilizează aceste informații pentru a adăuga informații suplimentare în directorul bin al JVM-ului nostru:

Deci, acum putem suna direct cererea noastră. Frumusețe!

76185 este un cod poștal valabil

Acesta este sfârșitul cunoașterii noastre cu Jigsaw. Am considerat o serie de exemple pentru a ilustra ceea ce se poate și ce nu se poate face cu Jigsaw și Java 9. Jigsaw aduce schimbări fundamentale care nu pot fi atât de ușor compensată prin utilizarea de expresii lambda, sau încercați-cu resurse. Toate tulchein noastre de la instrumente de asamblare ca Maven sau Gradle la IDE va ​​trebui să se adapteze la sistemul modular. La conferința JavaOne, Hans Dockter de la Gradle Inc. citiți un raport despre cum să începeți să scrieți un cod modular, chiar și în Java 8 și mai jos. Gradle efectuează o verificare a timpului de compilare și emite un defect dacă integritatea modulului este încălcată. Această oportunitate (experimentală) a fost inclusă în cea mai recentă versiune a clasei 2.9. Cu siguranta asteptam momente interesante!

Articole similare