Προγραμματισμός

Modularity στο Java 9: ​​Stacking with Project Jigsaw, Penrose και OSGi

Αυτό το άρθρο παρέχει μια επισκόπηση των προτάσεων, των προδιαγραφών και των πλατφορμών που στοχεύουν στο να καταστήσει την τεχνολογία Java πιο αρθρωτή στην Java 9. Θα συζητήσω παράγοντες που συμβάλλουν στην ανάγκη για μια πιο αρθρωτή αρχιτεκτονική Java, θα περιγράψω εν συντομία και θα συγκρίνω τις λύσεις που έχουν προταθεί, και να εισαγάγει τις τρεις ενημερώσεις αρθρωτότητας που έχουν προγραμματιστεί για το Java 9, συμπεριλαμβανομένου του δυνητικού τους αντίκτυπου στην ανάπτυξη Java.

Γιατί χρειαζόμαστε το Java modularity;

Αρθρωτότητα είναι μια γενική έννοια. Στο λογισμικό, ισχύει για τη σύνταξη και την εφαρμογή ενός προγράμματος ή ενός υπολογιστικού συστήματος ως μια σειρά από μοναδικές ενότητες, παρά ως ένα, μονολιθικό σχέδιο. Στη συνέχεια χρησιμοποιείται μια τυποποιημένη διεπαφή για να επιτρέψει στις ενότητες να επικοινωνούν. Ο διαχωρισμός ενός περιβάλλοντος κατασκευών λογισμικού σε ξεχωριστές ενότητες μας βοηθά να ελαχιστοποιήσουμε τη σύνδεση, να βελτιστοποιήσουμε την ανάπτυξη εφαρμογών και να μειώσουμε την πολυπλοκότητα του συστήματος.

Το Modularity επιτρέπει στους προγραμματιστές να κάνουν δοκιμές λειτουργικότητας μεμονωμένα και να συμμετέχουν σε προσπάθειες παράλληλης ανάπτυξης κατά τη διάρκεια ενός δεδομένου σπριντ ή έργου. Αυτό αυξάνει την απόδοση σε ολόκληρο τον κύκλο ζωής ανάπτυξης λογισμικού.

Μερικά χαρακτηριστικά γνωρίσματα μιας γνήσιας ενότητας είναι:

  • Μια αυτόνομη μονάδα ανάπτυξης (χαλαρή ζεύξη)
  • Μια συνεπής και μοναδική ταυτότητα (αναγνωριστικό ενότητας και έκδοση)
  • Εύκολα αναγνωρισμένες και ανακαλυφθείσες απαιτήσεις και εξαρτήσεις (τυπικές εγκαταστάσεις μεταγλώττισης και ανάπτυξης και μετα-πληροφορίες)
  • Μια ανοιχτή και κατανοητή διεπαφή (σύμβαση επικοινωνίας)
  • Κρυφές λεπτομέρειες εφαρμογής (ενθυλάκωση)

Τα συστήματα που έχουν κατασκευαστεί για την αποτελεσματική επεξεργασία ενοτήτων πρέπει να κάνουν τα εξής:

  • Υποστηρίξτε τη λειτουργικότητα και την εξάρτηση-ανακάλυψη στο χρόνο μεταγλώττισης
  • Εκτελέστε λειτουργικές μονάδες σε περιβάλλον χρόνου εκτέλεσης που υποστηρίζει εύκολη ανάπτυξη και αναδιάταξη χωρίς διακοπή λειτουργίας του συστήματος
  • Εφαρμόστε έναν κύκλο ζωής εκτέλεσης που είναι σαφής και στιβαρός
  • Παρέχετε εγκαταστάσεις για εύκολη καταγραφή και ανακάλυψη ενοτήτων

Οι αντικειμενοστρεφείς, εξαρτημένες, και προσανατολισμένες στις υπηρεσίες λύσεις έχουν όλοι προσπαθήσει να επιτρέψουν καθαρή αρθρωτότητα. Κάθε λύση έχει το δικό της σύνολο ιδιορρυθμιών που την εμποδίζουν να επιτύχει αρθρωτή τελειότητα, ωστόσο. Ας εξετάσουμε εν συντομία.

Τάξεις Java και αντικείμενα ως αρθρωτές κατασκευές

Δεν ανταποκρίνεται η αντικειμενοστρεφή φύση της Java στις απαιτήσεις του modularity; Σε τελική ανάλυση, ο αντικειμενοστραφής προγραμματισμός με Java τονίζει και μερικές φορές επιβάλλει τη μοναδικότητα, την ενθυλάκωση δεδομένων και τη χαλαρή σύζευξη. Ενώ αυτά τα σημεία είναι μια καλή αρχή, προσέξτε τις απαιτήσεις modularity που δεν είναι συναντάται από το αντικειμενοστρεφή πλαίσιο της Java: η ταυτότητα σε επίπεδο αντικειμένου είναι αναξιόπιστη. οι διεπαφές δεν έχουν εκδοθεί: και οι κλάσεις δεν είναι μοναδικές σε επίπεδο ανάπτυξης. Η χαλαρή ζεύξη είναι μια βέλτιστη πρακτική, αλλά σίγουρα δεν επιβάλλεται.

Η επαναχρησιμοποίηση τάξεων στην Java είναι δύσκολη όταν οι εξαρτήσεις τρίτων μερών χρησιμοποιούνται τόσο εύκολα. Εργαλεία συλλογής χρόνου όπως το Maven επιδιώκουν να αντιμετωπίσουν αυτό το μειονέκτημα. Οι συμβάσεις και οι κατασκευές μετά από το γεγονός όπως η έγχυση εξάρτησης και η αντιστροφή του ελέγχου βοηθούν τους προγραμματιστές στις προσπάθειές μας να ελέγξουν το περιβάλλον χρόνου εκτέλεσης και μερικές φορές πετυχαίνουν, ειδικά εάν χρησιμοποιούνται με αυστηρή πειθαρχία. Δυστυχώς, αυτή η κατάσταση αφήνει τη δουλειά της δημιουργίας ενός αρθρωτού περιβάλλοντος μέχρι ιδιόκτητων συμβάσεων και διαμορφώσεων πλαισίου.

Η Java προσθέτει επίσης χώρους ονομάτων πακέτων και ορατότητα πεδίου στο μείγμα ως μέσο για τη δημιουργία μηχανισμών αρθρωτού χρόνου μεταγλώττισης και ανάπτυξης. Αλλά αυτά τα χαρακτηριστικά γλώσσας παρακάμπτονται εύκολα, όπως θα εξηγήσω.

Πακέτα ως αρθρωτή λύση

Τα πακέτα προσπαθούν να προσθέσουν ένα επίπεδο αφαίρεσης στο τοπίο προγραμματισμού Java. Παρέχουν εγκαταστάσεις για μοναδικούς κωδικούς χώρου ονομάτων και περιβάλλοντα διαμόρφωσης. Δυστυχώς, ωστόσο, οι συμβάσεις πακέτων παρακάμπτονται εύκολα, οδηγώντας συχνά σε ένα περιβάλλον επικίνδυνων συζεύξεων χρόνου μεταγλώττισης.

Η κατάσταση της αρθρωτότητας στην Java αυτή τη στιγμή (εκτός από το OSGi, το οποίο θα συζητήσω σύντομα) επιτυγχάνεται συχνότερα χρησιμοποιώντας χώρους ονομάτων πακέτων, συμβάσεις JavaBeans και ιδιόκτητες διαμορφώσεις πλαισίου όπως αυτές που βρέθηκαν την άνοιξη.

Δεν είναι αρκετά αρθρωτά τα αρχεία JAR;

Τα αρχεία JAR και το περιβάλλον ανάπτυξης στο οποίο λειτουργούν βελτιώνουν σημαντικά τις πολλές συμβάσεις ανάπτυξης παλαιού τύπου που διατίθενται διαφορετικά. Ωστόσο, τα αρχεία JAR δεν έχουν εγγενή μοναδικότητα, εκτός από έναν αριθμό έκδοσης που σπάνια χρησιμοποιείται, ο οποίος κρύβεται σε μια δήλωση .jar. Το αρχείο JAR και το προαιρετικό μανιφέστο δεν χρησιμοποιούνται ως συμβάσεις modularity στο περιβάλλον χρόνου εκτέλεσης Java. Έτσι, τα ονόματα των πακέτων των τάξεων στο αρχείο και η συμμετοχή τους σε ένα classpath είναι τα μόνα μέρη της δομής JAR που προσδίδουν αρθρωτότητα στο περιβάλλον χρόνου εκτέλεσης.

Εν ολίγοις, τα JAR είναι μια καλή προσπάθεια διαμόρφωσης, αλλά δεν πληρούν όλες τις προϋποθέσεις για ένα πραγματικά αρθρωτό περιβάλλον. Τα πλαίσια και οι πλατφόρμες όπως το Spring και το OSGi χρησιμοποιούν μοτίβα και βελτιώσεις στην προδιαγραφή JAR για να παρέχουν περιβάλλοντα για την κατασκευή πολύ ικανών και αρθρωτών συστημάτων. Με την πάροδο του χρόνου, ωστόσο, ακόμη και αυτά τα εργαλεία θα υποκύψουν σε μια πολύ ατυχής παρενέργεια της προδιαγραφής JAR JAR hell!

Classpath / JAR κόλαση

Όταν το περιβάλλον εκτέλεσης Java επιτρέπει αυθαίρετα σύνθετους μηχανισμούς φόρτωσης JAR, οι προγραμματιστές γνωρίζουν ότι βρίσκονται κόλαση classpath ή JAR κόλαση. Ένας αριθμός διαμορφώσεων μπορεί να οδηγήσει σε αυτήν την κατάσταση.

Αρχικά, σκεφτείτε μια κατάσταση όπου ένας προγραμματιστής εφαρμογών Java παρέχει μια ενημερωμένη έκδοση της εφαρμογής και την έχει συσκευάσει σε ένα αρχείο JAR με το ίδιο ακριβώς όνομα με την παλιά έκδοση. Το περιβάλλον εκτέλεσης Java δεν παρέχει δυνατότητες επικύρωσης για τον προσδιορισμό του σωστού αρχείου JAR. Το περιβάλλον χρόνου εκτέλεσης θα φορτώνει απλά κλάσεις από το αρχείο JAR που βρίσκει πρώτα ή που ικανοποιεί έναν από πολλούς κανόνες classpath. Αυτό οδηγεί στην απροσδόκητη συμπεριφορά στην καλύτερη περίπτωση.

Μια άλλη περίπτωση του JAR hell προκύπτει όταν δύο ή περισσότερες εφαρμογές ή διαδικασίες εξαρτώνται από διαφορετικές εκδόσεις μιας βιβλιοθήκης τρίτων. Χρησιμοποιώντας τυπικές εγκαταστάσεις φόρτωσης κατηγορίας, μόνο μία έκδοση της βιβλιοθήκης τρίτων θα είναι διαθέσιμη κατά το χρόνο εκτέλεσης, οδηγώντας σε σφάλματα σε τουλάχιστον μία εφαρμογή ή διαδικασία.

Ένα πλήρες χαρακτηριστικό και αποτελεσματικό σύστημα λειτουργικών μονάδων Java θα διευκολύνει το διαχωρισμό του κώδικα σε διακριτές, εύκολα κατανοητές και χαλαρά συνδεδεμένες λειτουργικές μονάδες. Οι εξαρτήσεις πρέπει να προσδιορίζονται με σαφήνεια και να εφαρμόζονται αυστηρά. Πρέπει να είναι διαθέσιμες εγκαταστάσεις που επιτρέπουν την αναβάθμιση των ενοτήτων χωρίς να έχουν αρνητικό αντίκτυπο σε άλλες ενότητες. Ένα αρθρωτό περιβάλλον χρόνου εκτέλεσης θα πρέπει να επιτρέπει διαμορφώσεις που είναι συγκεκριμένες για έναν συγκεκριμένο τομέα ή κάθετη αγορά, μειώνοντας έτσι τον χρόνο εκκίνησης και το αποτύπωμα συστήματος του περιβάλλοντος.

Λύσεις modularity για Java

Μαζί με τα χαρακτηριστικά αρθρωτότητας που αναφέρονται μέχρι στιγμής, οι πρόσφατες προσπάθειες προσθέτουν μερικές ακόμη. Οι ακόλουθες λειτουργίες αποσκοπούν στη βελτιστοποίηση της απόδοσης και στην επέκταση του περιβάλλοντος χρόνου εκτέλεσης:

  • Τμηματοποιημένος πηγαίος κώδικας: Ο πηγαίος κώδικας διαχωρίζεται σε ξεχωριστά, προσωρινά αποθηκευμένα τμήματα, καθένα από τα οποία περιέχει έναν συγκεκριμένο τύπο μεταγλωττισμένου κώδικα. Οι στόχοι του οποίου περιλαμβάνουν παράλειψη κώδικα χωρίς μέθοδο κατά τη σάρωση απορριμμάτων, σταδιακή δημιουργία και καλύτερη διαχείριση μνήμης.
  • Εφαρμογές χρόνου κατασκευής: Κατασκευές γλωσσών για την επιβολή χώρων ονομάτων, εκδόσεων, εξαρτήσεων και άλλων.
  • Εγκαταστάσεις ανάπτυξης: Υποστήριξη για την ανάπτυξη κλιμακωτών περιβαλλόντων χρόνου εκτέλεσης σύμφωνα με συγκεκριμένες ανάγκες, όπως αυτές του περιβάλλοντος κινητής συσκευής.

Ορισμένες προδιαγραφές αρθρωτότητας και πλαίσια προσπάθησαν να διευκολύνουν αυτές τις δυνατότητες, και μερικές πρόσφατα ανέβηκαν στην κορυφή των προτάσεων για το Java 9. Παρακάτω ακολουθεί μια επισκόπηση των προτάσεων αρθρωτότητας Java.

JSR (Αίτηση προδιαγραφής Java) 277

Αυτήν τη στιγμή ανενεργό είναι το Java Specification Request (JSR) 277, το Java Module System. εισήχθη από την Sun τον Ιούνιο του 2005. Αυτή η προδιαγραφή κάλυψε τους περισσότερους από τους ίδιους τομείς με το OSGi. Όπως το OSGi, το JSR 277 ορίζει επίσης την ανακάλυψη, τη φόρτωση και τη συνοχή των ενοτήτων, με αραιή υποστήριξη για τροποποιήσεις χρόνου εκτέλεσης ή / και έλεγχο ακεραιότητας.

Τα μειονεκτήματα στο JSR 277 περιλαμβάνουν:

  • Χωρίς δυναμική φόρτωση και εκφόρτωση μονάδων / πακέτων
  • Δεν υπάρχουν έλεγχοι χρόνου εκτέλεσης για τη μοναδικότητα του χώρου στην τάξη

OSGi (Open Service Gateway Initiative)

Παρουσιάστηκε από τη Συμμαχία OSGI τον Νοέμβριο του 1998, η πλατφόρμα OSGI είναι η πιο ευρέως χρησιμοποιούμενη απάντηση στο modularity στην τυπική τυπική ερώτηση για την Java. Προς το παρόν στην έκδοση 6, η προδιαγραφή OSGi είναι ευρέως αποδεκτή και χρησιμοποιείται, ειδικά αργά.

Στην ουσία, το OSGi είναι ένα αρθρωτό σύστημα και μια πλατφόρμα υπηρεσιών για τη γλώσσα προγραμματισμού Java που εφαρμόζει ένα πλήρες και δυναμικό μοντέλο συστατικών με τη μορφή ενοτήτων, υπηρεσιών, αναπτυσσόμενων πακέτων και ούτω καθεξής.

Τα κύρια επίπεδα της αρχιτεκτονικής OSGI έχουν ως εξής:

  • Περιβάλλον εκτέλεσης: Το περιβάλλον Java (για παράδειγμα, Java EE ή Java SE) στο οποίο θα εκτελείται μια δέσμη.
  • Μονάδα μέτρησης: Όπου το πλαίσιο OSGi επεξεργάζεται τις αρθρωτές πτυχές ενός πακέτου. Τα μεταδεδομένα δέσμης επεξεργάζονται εδώ.
  • Κύκλος ζωής: Η προετοιμασία, η έναρξη και η διακοπή των πακέτων συμβαίνει εδώ.
  • Μητρώο υπηρεσιών: Όπου τα πακέτα παραθέτουν τις υπηρεσίες τους για να ανακαλύψουν άλλα πακέτα.

Ένα από τα μεγαλύτερα μειονεκτήματα του OSGi είναι η έλλειψη επίσημου μηχανισμού για την εγκατάσταση εγγενών πακέτων.

JSR 291

Το JSR 291 είναι ένα δυναμικό πλαίσιο για το Java SE που βασίζεται σε OSGi, βρίσκεται στο τελικό στάδιο ανάπτυξης. Αυτή η προσπάθεια επικεντρώνεται στη λήψη του OSGi σε mainstream Java, όπως έγινε για το κινητό περιβάλλον Java από το JSR 232.

JSR 294

Το JSR 294 ορίζει ένα σύστημα meta-modules και μεταβιβάζει την πραγματική υλοποίηση των pluggable modules (εκδόσεις, εξαρτήσεις, περιορισμοί κ.λπ.) σε εξωτερικούς παρόχους. Αυτή η προδιαγραφή εισάγει επεκτάσεις γλώσσας, όπως "superpackages" και ιεραρχικά συναφείς ενότητες, για τη διευκόλυνση του modularity. Η αυστηρή ενθυλάκωση και οι ξεχωριστές μονάδες συλλογής αποτελούν επίσης μέρος της εστίασης των προδιαγραφών. Το JSR 294 είναι προς το παρόν αδρανές.

Σχέδιο παζλ

Το Project Jigsaw είναι ο πιο πιθανός υποψήφιος για αρθρωτότητα στην Java 9. Το Jigsaw επιδιώκει να χρησιμοποιήσει δομές γλωσσών και διαμορφώσεις περιβάλλοντος για να ορίσει ένα επεκτάσιμο σύστημα λειτουργικών μονάδων για το Java SE. Οι πρωταρχικοί στόχοι του Jigsaw περιλαμβάνουν:

  • Καθιστώντας πολύ εύκολη την κλιμάκωση του χρόνου εκτέλεσης Java SE και του JDK σε μικρές συσκευές.
  • Βελτίωση της ασφάλειας του Java SE και του JDK απαγορεύοντας την πρόσβαση σε εσωτερικά API JDK και επιβάλλοντας και βελτιώνοντας SecurityManager.checkPackageAccess μέθοδος.
  • Βελτίωση της απόδοσης της εφαρμογής μέσω βελτιστοποιήσεων του υπάρχοντος κώδικα και διευκόλυνση των τεχνικών βελτιστοποίησης προοπτικών.
  • Απλοποίηση της ανάπτυξης εφαρμογών στο Java SE, επιτρέποντας τη δημιουργία βιβλιοθηκών και εφαρμογών από λειτουργικές μονάδες που δημιουργούνται από προγραμματιστές και από ένα αρθρωτό JDK
  • Απαίτηση και επιβολή ενός περιορισμένου συνόλου περιορισμών έκδοσης

JEP (Πρόταση βελτίωσης Java) 200

Το Java Enhancement Proposal 200 που δημιουργήθηκε τον Ιούλιο του 2014, επιδιώκει να ορίσει μια αρθρωτή δομή για το JDK. Το JEP 200 βασίζεται στο Jigsaw framework για να διευκολύνει την τμηματοποίηση του JDK, σύμφωνα με τα Java 8 Compact Profiles, σε σύνολα ενοτήτων που μπορούν να συνδυαστούν σε χρόνο μεταγλώττισης, χρόνο κατασκευής και χρόνο ανάπτυξης. Αυτοί οι συνδυασμοί ενοτήτων μπορούν στη συνέχεια να αναπτυχθούν ως περιβάλλοντα χρόνου εκτέλεσης με κλίμακα που αποτελούνται από λειτουργικές μονάδες συμβατές με Jigsaw.

JEP 201

Το JEP 201 επιδιώκει να βασιστεί στο Jigsaw για να αναδιοργανώσει τον πηγαίο κώδικα JDK σε ενότητες. Αυτές οι ενότητες μπορούν στη συνέχεια να μεταγλωττιστούν ως ξεχωριστές μονάδες από ένα βελτιωμένο σύστημα κατασκευής που επιβάλλει τα όρια των μονάδων. Το JEP 201 προτείνει ένα σχήμα αναδιάρθρωσης πηγαίου κώδικα σε ολόκληρο το JDK που δίνει έμφαση στα όρια των μονάδων στο ανώτερο επίπεδο των δένδρων πηγαίου κώδικα.

Πενρόζη

Το Penrose θα διαχειριζόταν τη διαλειτουργικότητα μεταξύ Jigsaw και OSGi. Συγκεκριμένα, θα διευκόλυνε τη δυνατότητα τροποποίησης των μικρο-πυρήνων OSGi, προκειμένου οι δέσμες που εκτελούνται στον τροποποιημένο πυρήνα να χρησιμοποιούν μονάδες Jigsaw. Βασίζεται στη χρήση του JSON για την περιγραφή ενοτήτων.

Σχέδια για Java 9

Το Java 9 είναι μια μοναδική μεγάλη έκδοση για Java. Αυτό που το κάνει μοναδικό είναι η εισαγωγή αρθρωτών εξαρτημάτων και τμημάτων σε ολόκληρο το JDK. Τα κύρια χαρακτηριστικά που υποστηρίζουν τη διαμόρφωση είναι:

  • Αρθρωτός πηγαίος κώδικας: Στην Java 9, το JRE και το JDK θα αναδιοργανωθούν σε διαλειτουργικές ενότητες. Αυτό θα επιτρέψει τη δημιουργία κλιμακούμενων χρόνων εκτέλεσης που μπορούν να εκτελεστούν σε μικρές συσκευές.
  • Τμηματοποιημένη προσωρινή μνήμη κώδικα: Αν και δεν είναι αυστηρά μια αρθρωτή εγκατάσταση, η νέα τμηματοποιημένη κρυφή μνήμη κώδικα Java 9 θα ακολουθήσει το πνεύμα της διαμόρφωσης και θα απολαμβάνει μερικά από τα ίδια οφέλη. Η νέα προσωρινή μνήμη κώδικα θα λάβει έξυπνες αποφάσεις για τη συλλογή τμημάτων κώδικα που έχουν συχνά πρόσβαση σε εγγενή κώδικα και θα τα αποθηκεύει για βελτιστοποιημένη αναζήτηση και μελλοντική εκτέλεση. Ο σωρός θα χωριστεί επίσης σε 3 ξεχωριστές ενότητες: κωδικός χωρίς μέθοδο που θα αποθηκεύεται μόνιμα στην προσωρινή μνήμη. κωδικός που έχει δυνητικά μεγάλο κύκλο ζωής (γνωστός ως "κωδικός χωρίς προφίλ") · και κώδικα που είναι παροδικός (γνωστός ως "κωδικοποιημένος κώδικας").
  • Εφαρμογές χρόνου κατασκευής: Το σύστημα κατασκευής θα βελτιωθεί, μέσω του JEP 201, για την κατάρτιση και την επιβολή ορίων λειτουργικής μονάδας.
  • Εγκαταστάσεις ανάπτυξης: Εργαλεία θα παρέχονται εντός του έργου Jigsaw που θα υποστηρίζει τα όρια της μονάδας, τους περιορισμούς και τις εξαρτήσεις κατά το χρόνο ανάπτυξης.

Έκδοση πρώιμης πρόσβασης Java 9

Ενώ η ακριβής ημερομηνία κυκλοφορίας του Java 9 παραμένει μυστήριο, μπορείτε να κατεβάσετε μια έκδοση πρώιμης πρόσβασης στο Java.net.

Συμπερασματικά

Αυτό το άρθρο ήταν μια επισκόπηση του modularity μέσα στην πλατφόρμα Java, συμπεριλαμβανομένων των προοπτικών modularity στην Java 9. Εξήγησα πόσο μακροχρόνια ζητήματα όπως το classpath hell συμβάλλουν στην ανάγκη για μια πιο αρθρωτή αρχιτεκτονική Java και συζήτησαν μερικές από τις πιο πρόσφατες νέες modularity προτεινόμενα χαρακτηριστικά για Java. Στη συνέχεια περιέγραψα και συμφραζόμουν με καθεμία από τις προτάσεις ή πλατφόρμες αρθρωτότητας Java, συμπεριλαμβανομένων των OSGi και Project Jigsaw.

Η ανάγκη για μια πιο αρθρωτή αρχιτεκτονική Java είναι ξεκάθαρη. Οι τρέχουσες προσπάθειες έχουν μειωθεί, αν και το OSGi έρχεται πολύ κοντά. Για την έκδοση Java 9, το Project Jigsaw και το OSGi θα είναι οι κύριοι παίκτες στον αρθρωτό χώρο για Java, με το Penrose να παρέχει πιθανώς την κόλλα μεταξύ τους.

Αυτή η ιστορία, "Modularity in Java 9: ​​Stacking up with Project Jigsaw, Penrose και OSGi" δημοσιεύθηκε αρχικά από το JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found