Geen resultaten gevonden

Uw zoekopdracht heeft geen resultaten opgeleverd.

We raden u aan het volgende te proberen om te vinden wat u zoekt:

  • Controleer de spelling van het trefwoord in uw zoekopdracht.
  • Gebruik synoniemen voor het trefwoord dat u hebt getypt. Probeer bijvoorbeeld “applicatie” in plaats van “software”.
  • Probeer een van de onderstaande populaire zoekopdrachten.
  • Start een nieuwe zoekopdracht.
Populaire vragen

 

Java 9 | Fragment

Java 9-modules begrijpen

Wat dat zijn en hoe we ze gebruiken

Door Paul Deitel


Paul Deitel

Paul Deitel

In dit artikel introduceer ik het Java 9 Platform Module System (JPMS), de belangrijkste nieuwe software engineering technologie in het bestaan van Java. Modulariteit, het resultaat van Project Jigsaw, helpt ontwikkelaars op alle niveaus productiever te zijn bij het bouwen, onderhouden en ontwikkelen van met name grote softwaresystemen.

Wat is een module?

Modulariteit voegt een hoger aggregatieniveau toe boven de pakketten. Het belangrijkste nieuwe taalelement is de module: een herbruikbare groep gerelateerde pakketten met een unieke naam, maar ook resources (zoals afbeeldingen en XML-bestanden) en een module-descriptor voor de specificatie van

  • de naam van de module
  • de afhankelijkheden van de module (d.w.z. andere modules waarvan deze module afhankelijk is)
  • de pakketten die hij expliciet beschikbaar stelt voor andere modules (alle andere pakketten in de module zijn impliciet niet beschikbaar voor andere modules)
  • de services die hij biedt
  • de services die hij gebruikt
  • andere modules waarmee reflectie mogelijk is

Historie

Het Java SE-platform bestaat al sinds 1995. Er zijn nu ongeveer 10 miljoen ontwikkelaars die het gebruiken om van alles te bouwen, van kleine apps voor apparaten met beperkte middelen, zoals in het Internet of Things (IoT) en andere ingebouwde apparaten, tot omvangrijke systemen, essentieel voor bedrijfsvoering en missie. Er zijn enorme hoeveelheden bestaande code beschikbaar, maar tot nu toe was het Java-platform vooral een monolithische one-size-fits-all oplossing. In de loop der jaren zijn er diverse inspanningen gedaan om Java modulair te maken, maar die zijn niet populair en geen enkele kan werkelijk dienen om het Java-platform te modulariseren.

Het modulariseren van het Java SE-platform was een uitdaging en we hebben er heel wat jaren aan gewerkt. JSR 277: Java Module System verscheen oorspronkelijk in 2005 voor Java 7. Dit JSR is later vervangen door JSR 376: Java Platform Module System, dat bedoeld was voor Java 8. Het Java SE-platform is nu modulair in Java 9, maar pas nadat Java 9 was uitgesteld tot september 2017.

Doelen

Elke module moet expliciet zijn afhankelijkheden vermelden.

Volgens JSR 376 heeft het modulariseren van het Java SE-platform de volgende hoofddoelen

  • Betrouwbare configuratie - modulariteit biedt mechanismen voor het expliciet benoemen van afhankelijkheden tussen modules op een manier die tijdens het compileren en tijdens de uitvoering wordt herkend. Het systeem kan deze afhankelijkheden doorlopen om de subset te bepalen van alle benodigde modules om uw applicatie te ondersteunen.
  • Sterke inkapseling - de pakketten in een module zijn alleen toegankelijk voor andere modules als de module ze expliciet exporteert. Zelfs dan kan een andere module die pakketten niet gebruiken, tenzij expliciet is vermeld dat de capaciteiten van die andere module zijn vereist. Dit verbetert de platformbeveiliging, doordat er minder klassen blootstaan aan mogelijke aanvallen. U zult merken dat deze eventuele modulariteit helpt om strakkere, meer logische ontwerpen te realiseren.
  • Schaalbaar Java-platform - vroeger was het Java-platform een monoliet bestaande uit een enorm aantal pakketten, dat lastig was om te ontwikkelen, onderhouden en evolueren. Gebruik van subsets was niet gemakkelijk. Het platform is nu gemodulariseerd in 95 modules (aantal kan veranderen als Java zich ontwikkelt). U kunt aangepaste runtimes maken, alleen voor modules die u nodig hebt voor uw apps of de apparaten waarop u zich richt. Als een apparaat bijvoorbeeld geen GUI's ondersteunt, kunt u een runtime maken die geen GUI-modules bevat, waardoor de runtime aanzienlijk kleiner wordt.
  • Grotere platformintegriteit - vóór Java 9 konden veel klassen op het platform worden gebruikt die niet bedoeld waren voor gebruik door de klassen van een app. Door een sterke inkapseling zijn deze interne API's echt ingekapseld en verborgen voor apps die het platform gebruiken. Het migreren van bestaande code naar het modulaire Java 9 kan hierdoor problematisch worden als uw code afhankelijk is van interne API's.
  • Verbeterde prestaties - JVM gebruikt diverse optimalisatietechnieken om de applicatie beter te laten presteren. JSR 376 geeft aan dat deze technieken effectiever zijn als vooraf bekend is dat de vereiste typen alleen in de specifieke modules zitten.

Lijst met JDK’s modules

JEP 200: MODULAIRE JDK

JEP 201: MODULAIRE BRONCODE

JEP 220: MODULAIRE RUNTIME-IMAGES

JEP 260: MEEST INTERNE API'S INKAPSELEN

JEP 261: MODULESYSTEEM

JEP 275: MODULAIRE JAVA-APPLICATIEPAKKETTEN

JEP 282: JLINK: DE JAVA LINKER

JSR 376: JAVA PLATFORM MODULESYSTEEM

JSR 379: JAVA SE 9

Tabel 1. JEP's en JSR's voor Java-modulariteit

Een cruciaal aspect van Java 9 is dat JDK in modules wordt verdeeld om verschillende configuraties te ondersteunen. (Raadpleeg "JEP 200: Modulaire JDK." Alle JEP's en JSR's voor Java-modulariteit worden getoond in tabel 1.) Gebruik het Java-commando uit JDK's binmap met de optie --list-modules, zoals in: 

java --list-modules

Toont een lijst met JDK's moduleset, met de standaardmodules voor de implementatie van de Java Language SE Specification (namen beginnend met java), JavaFX-modules (namen beginnend met javafx), JDK-specifieke modules (namen beginnend met jdk) en Oracle-specifieke modules (namen beginnend met oracle). Elke modulenaam wordt gevolgd door een versie-string. @9 geeft aan dat de module tot Java 9 behoort.

Moduleverklaringen

Zoals we al zeiden, moet een module een module-descriptor bieden: metadata die de afhankelijkheden van de module specificeert, de pakketten die de module beschikbaar stelt voor andere modules etc. Een module-descriptor is de gecompileerde versie van een moduleverklaring, die is gedefinieerd in een bestand met de naam module-info.java. Elke moduleverklaring begint met het sleutelwoord module, gevolgd door een unieke modulenaam en een modulebody tussen accolades, zoals in:

Een belangrijke reden voor het modulesysteem is een sterke inkapseling.

module modulenaam {
}

De hoofdtekst van de moduleverklaring kan leeg zijn of verschillende module-instructies bevatten, waaronder requires, exports, provides…with, uses en opens (die we allemaal bespreken). Zoals u later zult zien, wordt bij het compileren van de moduleverklaring de module-descriptor aangemaakt, die wordt opgeslagen in een bestand met de naam module-info.class in de hoofdmap van de module. Hier introduceren we kort elke module-instructie. Daarna presenteren we de eigenlijke moduleverklaringen.

De sleutelwoorden exports, module, open, opens, provides, requires, uses, with, evenals to en transitive, die we later introduceren, zijn beperkte sleutelwoorden. Het zijn sleutelwoorden alleen in moduleverklaringen en ze kunnen overal in uw code als ID's worden gebruikt.

requires. Een module-instructie requires geeft aan dat deze module afhankelijk is van een andere module. Deze relatie wordt een module-afhankelijkheid genoemd. Elke module moet expliciet zijn afhankelijkheden vermelden. Als module A module B vereist, zeggen we dat module A module B leest en dat module B wordt gelezen door module A. Als u een afhankelijkheid van een andere module wilt aangeven, gebruikt u requires, zoals in:

requires modulename;

Er is ook een instructie requires static om aan te geven dat een module vereist is tijdens het compileren, maar optioneel is tijdens runtime. Dit noemen we een optionele afhankelijkheid, die we niet bespreken in deze inleiding.

vereist transitief - impliciete leesbaarheid. Als u een afhankelijkheid van een andere module wilt aangeven, zodat andere modules die uw module lezen ook die afhankelijkheid lezen (ook wel impliciete leesbaarheid genoemd), gebruikt u requires transitive, zoals in:

requires transitive modulename;

Bekijk de volgende instructie uit de moduleverklaring van java.desktop:

requires transitive java.xml

In dit geval leest elke module die java.desktop leest impliciet ook java.xml. Als een methode van de module java.desktop bijv. een type van de module java.xml retourneert, wordt de code in modules die java.desktop lezen afhankelijk van java.xml. Zonder de instructie requires transitive in de moduleverklaring van java.desktop worden zulke afhankelijke modules niet gecompileerd tenzij ze expliciet java.xml lezen.

Volgens JSR 379 moeten Java SE's standaardmodules in alle gevallen impliciete leesbaarheid verlenen, zoals hier beschreven. Een Java SE-standaardmodule kan ook afhankelijk zijn van niet-standaardmodules, maar mag er geen impliciete leesbaarheid aan toekennen. Hierdoor kan code alleen op basis van Java SE-standaardmodules worden overgedragen aan Java SE-implementaties.

exports and exports…to. Een module-instructie exports specificeert één van de pakketten van de module waarvan het type public (en het geneste type public en protected) toegankelijk moet zijn voor code in alle andere modules. Met een instructie exports…to kunt u in een door komma's gescheiden lijst precies opgeven welke module of modulecode toegang heeft tot het geëxporteerde pakket, de zogenaamde gekwalificeerde export. 

uses. Een module-instructie uses specificeert een service die door deze module wordt gebruikt, waardoor de module een servicegebruiker wordt. Een service is een object van een klasse die de interface implementeert of de klasse abstract uitbreidt die is opgegeven in de instructie uses.

provides…with. Een module-instructie provides…with-geeft aan dat een module een service-implementatie biedt, waardoor de module een serviceprovider wordt. Het gedeelte provides van de instructie specificeert een interface- of abstract-klasse die wordt vermeld in de instructie uses van een module en het gedeelte with van de instructie specificeert de naam van de serviceprovider-klasse die de interface implementeert of die de abstract-klasse uitbreidt.

open, opens, and opens…to. Vóór Java 9 kon reflectie worden gebruikt om meer te weten te komen over alle typen in een pakket en alle leden van een type, zelfs de private-leden, of u deze mogelijkheid nu wel of niet wilde toelaten. Niets was dus echt ingekapseld.

Een belangrijke reden voor het modulesysteem is een sterke inkapseling. Een type in een module is standaard niet toegankelijk voor andere modules, tenzij het een openbaar type is en u zijn pakket exporteert. U toont alleen de pakketten die u wilt weergeven. Bij Java 9 geldt dit ook voor reflectie.

Alleen runtime-toegang tot pakket toestaan. Opent module-instructie van het formulier

opent pakket

geeft aan dat de public-typen (en de geneste public- en protected-typen) van een specifiek pakket alleen tijdens runtime toegankelijk zijn voor code in andere modules. Ook zijn alle typen in het opgegeven pakket (en alle leden van het type) toegankelijk via reflectie.

Verlening van runtime-toegang tot een pakket door specifieke modules. Een opens…to module-instructie van het formulier

opent pakket naar door komma's gescheiden lijst met modules

geeft aan dat de typen public van een specifiek pakket (en de geneste typen public en protected) alleen tijdens runtime toegankelijk zijn voor code in de vermelde modules. Alle typen in het opgegeven pakket (en alle leden van het type) zijn via reflectie toegankelijk voor code in de opgegeven modules.

Alleen runtime-toegang toestaan tot alle pakketten in een module. Als alle pakketten in een bepaalde module tijdens runtime en via reflectie toegankelijk moeten zijn voor alle andere modules, kunt u de volledige module openen, zoals in:

open module modulename {
   // module directives

Standaard reflectie

Standaard kan een module met runtime-reflectieve toegang tot een pakket de typen public van het pakket zien (en de geneste typen public en protected). De code in andere modules heeft echter toegang tot alle typen in het weergegeven pakket en alle leden binnen die typen, inclusief private leden via setAccessible, zoals in eerdere Java-versies.

Zie Oracle's documentatie voor meer informatie over setAccessible en reflectie.


Paul Deitel, CEO en Chief Technical Officer bij Deitel & Associates, is afgestudeerd aan het MIT met 35 jaar ervaring in computing Hij is een voorvechter van Java en programmeert al ruim 22 jaar in deze taal. Hij en zijn coauteur, Dr. Harvey M. Deitel is wereldwijd de best verkochte auteur op het gebied van programmeertaal. Paul heeft Java-, Android-, iOS-, C#-, C++-, C- en internet-programmeercursussen verzorgd voor internationale klanten in de industrie, overheid en academische wereld.


OPMERKING: Dit artikel bevat delen van Java Magazine september/oktober 2017.

Meer informatie