Programmering

Modularitet i Java 9: ​​Sammenbygning med Project Jigsaw, Penrose og OSGi

Denne artikel giver en oversigt over forslag, specifikationer og platforme, der sigter mod at gøre Java-teknologi mere modulær i Java 9. Jeg vil diskutere faktorer, der bidrager til behovet for en mere modulær Java-arkitektur, kort beskrive og sammenligne de løsninger, der er blevet foreslået, og introducere de tre modularitetsopdateringer, der er planlagt til Java 9, herunder deres potentielle indvirkning på Java-udvikling.

Hvorfor har vi brug for Java-modularitet?

Modularitet er et generelt begreb. I software gælder det for skrivning og implementering af et program eller computersystem som et antal unikke moduler snarere end som et enkelt, monolitisk design. En standardiseret grænseflade bruges derefter til at gøre det muligt for modulerne at kommunikere. At opdele et miljø af softwarekonstruktioner i forskellige moduler hjælper os med at minimere kobling, optimere applikationsudvikling og reducere systemkompleksiteten.

Modularitet gør det muligt for programmører at udføre funktionstest isoleret og deltage i parallel udviklingsindsats under en given sprint eller et givet projekt. Dette øger effektiviteten gennem hele softwareudviklingslivscyklussen.

Nogle karakteristiske egenskaber ved et ægte modul er:

  • En selvstændig implementeringsenhed (løs kobling)
  • En ensartet og unik identitet (modul-id og version)
  • Nemt identificerede og opdagede krav og afhængigheder (standard kompileringstid og installationsfaciliteter og metainformation)
  • En åben og forståelig grænseflade (kommunikationskontrakt)
  • Skjulte implementeringsoplysninger (indkapsling)

Systemer, der er bygget til effektivt at behandle moduler, skal gøre følgende:

  • Støtte modularitet og afhængighedsopdagelse på kompileringstidspunktet
  • Udfør moduler i et runtime-miljø, der understøtter let implementering og omplacering uden systemnedetid
  • Implementere en eksekvering livscyklus, der er klar og robust
  • Giv faciliteter til nem registrering og opdagelse af moduler

Objektorienterede, komponentorienterede og serviceorienterede løsninger har alle forsøgt at muliggøre ren modularitet. Hver løsning har sit eget sæt quirks, der dog forhindrer den i at opnå modulær perfektion. Lad os kort overveje.

Java-klasser og objekter som modulkonstruktioner

Opfylder Java's objektorienterede natur ikke kravene til modularitet? Når alt kommer til alt, understreger objektorienteret programmering med Java og undertiden håndhæver unikhed, datakapsling og løs kobling. Selvom disse punkter er en god start, skal du være opmærksom på kravene til modularitet ikke er mødt af Java's objektorienterede ramme: identitet på objektniveau er upålidelig; grænseflader er ikke versioneret: og klasser er ikke unikke på implementeringsniveau. Løs kobling er en bedste praksis, men bestemt ikke håndhævet.

Genbrug af klasser i Java er vanskeligt, når tredjepartsafhængigheder misbruges så let. Kompileringstidsværktøjer som Maven søger at løse denne mangel. Faktiske sprogkonventioner og -konstruktioner som afhængighedsinjektion og inversion-of-control hjælper udviklere i vores forsøg på at kontrollere runtime-miljøet, og nogle gange lykkes det, især hvis det bruges med streng disciplin. Desværre efterlader denne situation opgaven med at skabe et modulært miljø op til proprietære rammekonventioner og konfigurationer.

Java tilføjer også pakkenavneområder og rækkevidde til mixet som et middel til at skabe modulære mekanismer til kompileringstid og implementeringstid. Men disse sprogfunktioner kan let overgås, som jeg vil forklare.

Pakker som en modulær løsning

Pakker forsøger at tilføje et abstraktionsniveau til Java-programmeringslandskabet. De giver faciliteter til unikke kodende navneområder og konfigurationskontekster. Desværre er emballagekonventioner let omgået, hvilket ofte fører til et miljø med farlige kompileringskoblinger.

Modularitetens tilstand i Java i øjeblikket (bortset fra OSGi, som jeg snart vil diskutere) opnås oftest ved hjælp af pakkenavneområder, JavaBeans-konventioner og proprietære rammekonfigurationer som dem, der blev fundet i foråret.

Er JAR-filer ikke modulære nok?

JAR-filer og det implementeringsmiljø, hvori de fungerer, forbedrer i høj grad de mange ældre implementeringskonventioner, der ellers er tilgængelige. Men JAR-filer har ingen iboende unikhed bortset fra et sjældent anvendt versionsnummer, der er skjult i et .jar-manifest. JAR-filen og det valgfrie manifest bruges ikke som modularitetskonventioner i Java-runtime-miljøet. Så pakkenavnene på klasser i filen og deres deltagelse i en klassesti er de eneste dele af JAR-strukturen, der giver runtime-miljøet modularitet.

Kort sagt er JAR'er et godt forsøg på modulering, men de opfylder ikke alle kravene til et virkelig modulært miljø. Rammer og platforme som Spring og OSGi bruger mønstre og forbedringer af JAR-specifikationen for at give miljøer til opbygning af meget dygtige og modulære systemer. Over tid vil imidlertid selv disse værktøjer bukke under for en meget uheldig bivirkning af JAR-specifikationen JAR helvede!

Klassesti / JAR helvede

Når Java-runtime-miljøet giver mulighed for vilkårligt komplekse JAR-indlæsningsmekanismer, ved udviklere, at de er i klassesti helvede eller JAR helvede. Et antal konfigurationer kan føre til denne tilstand.

Overvej først en situation, hvor en Java-applikationsudvikler leverer en opdateret version af applikationen og har pakket den i en JAR-fil med nøjagtigt samme navn som den gamle version. Java runtime-miljøet indeholder ingen valideringsfaciliteter til at bestemme den korrekte JAR-fil. Runtime-miljøet indlæser simpelthen klasser fra JAR-filen, som den finder først, eller som opfylder en af ​​mange klassesti-regler. Dette fører i bedste fald til uventet opførsel.

En anden forekomst af JAR-helvede opstår, hvor to eller flere applikationer eller processer afhænger af forskellige versioner af et tredjepartsbibliotek. Ved hjælp af standardklasseindlæsningsfaciliteter vil kun en version af tredjepartsbiblioteket være tilgængelig under kørsel, hvilket fører til fejl i mindst en applikation eller proces.

Et komplet og effektivt Java-modulsystem skal lette adskillelse af kode i forskellige, let forståelige og løst koblede moduler. Afhængigheder skal være tydeligt specificeret og strengt håndhævet. Der skal være faciliteter, der gør det muligt at opgradere moduler uden at have en negativ effekt på andre moduler. Et modulært runtime-miljø skal muliggøre konfigurationer, der er specifikke for et bestemt domæne eller vertikalt marked, hvilket reducerer opstartstiden og systemets fodaftryk for miljøet.

Modularitetsløsninger til Java

Sammen med de hidtil nævnte modularitetsfunktioner tilføjer den seneste indsats et par mere. Følgende funktioner er beregnet til at optimere ydeevnen og muliggøre udvidelse af runtime-miljøet:

  • Segmenteret kildekode: Kildekode adskilt i forskellige, cachelagrede segmenter, som hver indeholder en bestemt type kompileret kode. Målene inkluderer at springe kode, der ikke er metode over, under fejning af skrald, trinvis opbygning og bedre hukommelsesstyring.
  • Håndhævelser under opførelse: Sprog konstruerer til at håndhæve navneområder, versionering, afhængigheder og andre.
  • Implementeringsfaciliteter: Understøttelse af implementering af skalerede runtime-miljøer i henhold til specifikke behov, såsom dem i et mobilt enhedsmiljø.

En række modularitetsspecifikationer og rammer har forsøgt at lette disse funktioner, og nogle få er for nylig steget til toppen i forslag til Java 9. En oversigt over Java-modularitetsforslag er nedenfor.

JSR (Java Specification Request) 277

I øjeblikket inaktiv er Java Specification Request (JSR) 277, Java-modulsystemet; introduceret af Sun i juni 2005. Denne specifikation dækkede de fleste af de samme områder som OSGi. Ligesom OSGi definerer JSR 277 også opdagelse, indlæsning og konsistens af moduler med sparsom support til runtime-ændringer og / eller kontrol af integritet.

Ulemper ved JSR 277 inkluderer:

  • Ingen dynamisk indlæsning og aflæsning af moduler / bundter
  • Ingen runtime-kontrol for klasse-plads unikhed

OSGi (Open Service Gateway Initiative)

OSGI-platformen blev introduceret af OSGI Alliance i november 1998 og er det mest anvendte modularitetssvar på det formelle standardspørgsmål til Java. I øjeblikket ved frigivelse 6 er OSGi-specifikationen bredt accepteret og brugt, især for sent.

I det væsentlige er OSGi et modulært system og en serviceplatform til Java-programmeringssproget, der implementerer en komplet og dynamisk komponentmodel i form af moduler, tjenester, implementerbare bundter osv.

De primære lag i OSGI-arkitekturen er som følger:

  • Udførelsesmiljø: Java-miljøet (f.eks. Java EE eller Java SE), hvorunder en pakke kører.
  • Modul: Hvor OSGi-rammen behandler de modulære aspekter af en pakke. Bundemetadata behandles her.
  • Livscyklus: Initialisering, start og stop af bundter sker her.
  • Service-register: Hvor bundter viser deres tjenester, som andre bundter kan opdages.

En af de største ulemper ved OSGi er manglen på en formel mekanisme til installation af native-pakker.

JSR 291

JSR 291 er en dynamisk komponentramme til Java SE, der er baseret på OSGi, og er i øjeblikket i den sidste fase af udviklingen. Denne indsats fokuserer på at tage OSGi ind i mainstream Java, som det blev gjort for Java-mobile miljøet af JSR 232.

JSR 294

JSR 294 definerer et system af metamoduler og delegerer den aktuelle udførelsesform for tilslutningsmoduler (versioner, afhængigheder, begrænsninger osv.) Til eksterne udbydere. Denne specifikation introducerer sprogudvidelser, såsom "superpakker" og hierarkisk relaterede moduler, for at lette modularitet. Streng indkapsling og særskilte kompilationsenheder er også en del af specifikationens fokus. JSR 294 er i øjeblikket sovende.

Projekt puslespil

Project Jigsaw er den mest sandsynlige kandidat til modularitet i Java 9. Jigsaw søger at bruge sprogkonstruktioner og miljøkonfigurationer til at definere et skalerbart modulsystem til Java SE. De primære mål for Jigsaw inkluderer:

  • Gør det meget let at skalere Java SE-runtime og JDK ned til små enheder.
  • Forbedring af sikkerheden i Java SE og JDK ved at forbyde adgang til interne JDK API'er og ved at håndhæve og forbedre SecurityManager.checkPackageAccess metode.
  • Forbedring af applikationsydelse via optimeringer af eksisterende kode og letter fremadrettede programoptimeringsteknikker.
  • Forenkling af applikationsudvikling inden for Java SE ved at gøre det muligt at konstruere biblioteker og applikationer fra udviklerbidragte moduler og fra et modulært JDK
  • Kræver og håndhæver et endeligt sæt af begrænsninger i versionen

JEP (Java Enhancement Proposal) 200

Java Enhancement Proposal 200 oprettet i juli 2014 søger at definere en modulstruktur for JDK. JEP 200 bygger på Jigsaw-rammen for at lette segmentering af JDK ifølge Java 8 Compact Profiles i sæt af moduler, der kan kombineres på kompileringstid, byggetid og implementeringstid. Disse kombinationer af moduler kan derefter implementeres som nedskalerede runtime-miljøer, der er sammensat af Jigsaw-kompatible moduler.

JEP 201

JEP 201 søger at bygge videre på Jigsaw for at omorganisere JDK-kildekoden i moduler. Disse moduler kan derefter kompileres som forskellige enheder af et forbedret build-system, der håndhæver modulgrænser. JEP 201 foreslår en kildekodestruktureringsplan i hele JDK, der understreger modulgrænser på det øverste niveau af kildekodetræer.

Penrose

Penrose ville styre interoperabilitet mellem Jigsaw og OSGi. Specifikt ville det lette muligheden for at ændre OSGi-mikrokerner, så bundter, der kører i den modificerede kerne, bruger Jigsaw-moduler. Det er afhængigt af at bruge JSON til at beskrive moduler.

Planer for Java 9

Java 9 er en unik større udgivelse til Java. Det, der gør det unikt, er dets introduktion af modulære komponenter og segmenter gennem hele JDK. De primære funktioner, der understøtter modularisering, er:

  • Modulkildekode: I Java 9 vil JRE og JDK blive omorganiseret til interoperable moduler. Dette muliggør oprettelse af skalerbare driftstider, der kan udføres på små enheder.
  • Segmenteret kode cache: Selvom det ikke strengt taget er en modulopbygget facilitet, vil den nye segmenterede kodecache i Java 9 følge modulariseringens ånd og nyde nogle af de samme fordele. Den nye kodecache tager intelligente beslutninger om at kompilere ofte tilgængelige kodesegmenter til den oprindelige kode og gemme dem til optimeret opslag og fremtidig udførelse. Bunken vil også blive opdelt i 3 forskellige enheder: kode, der ikke er metode, der gemmes permanent i cachen; kode, der har en potentielt lang livscyklus (kendt som "ikke-profileret kode"); og kode, der er forbigående (kendt som "profileret kode").
  • Håndhævelser under opførelse: Bygningssystemet forbedres via JEP 201 til at kompilere og håndhæve modulgrænser.
  • Implementeringsfaciliteter: Værktøjer leveres inden for Jigsaw-projektet, der understøtter modulgrænser, begrænsninger og afhængigheder ved implementeringstidspunktet.

Java 9 frigivelse af tidlig adgang

Mens den nøjagtige udgivelsesdato for Java 9 stadig er et mysterium, kan du downloade en frigivelse af tidlig adgang på Java.net.

Afslutningsvis

Denne artikel har været en oversigt over modularitet inden for Java-platformen, herunder udsigter til modularitet i Java 9. Jeg forklarede, hvordan mangeårige emner som klassesti helvede bidrager til behovet for en mere modulær Java-arkitektur og diskuterede nogle af de nyeste nye modulariteter funktioner foreslået til Java. Derefter beskrev og kontekstualiserede jeg hvert af Java-modularitetsforslag eller -platforme, herunder OSGi og Project Jigsaw.

Behovet for en mere modulær Java-arkitektur er klart. Nuværende forsøg er gået kort, selvom OSGi kommer meget tæt på. Til Java 9-udgivelsen vil Project Jigsaw og OSGi være de vigtigste spillere i det modulære rum til Java, hvor Penrose muligvis giver limen imellem dem.

Denne historie, "Modularity in Java 9: ​​Stacking up with Project Jigsaw, Penrose, and OSGi" blev oprindeligt udgivet af JavaWorld.