socialgekon.com
  • Κύριος
  • Συμβουλές Και Εργαλεία
  • Άνθρωποι Προϊόντων Και Ομάδες
  • Διεπαφή Ιστού
  • Σχεδιασμός Για Κινητά
Διεπαφή Ιστού

Advanced Java Class Tutorial: Ένας οδηγός για Επαναφόρτωση κλάσης

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

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

Ρύθμιση χώρου εργασίας

Όλος ο πηγαίος κώδικας για αυτό το σεμινάριο μεταφορτώνεται στο GitHub εδώ .



Για να εκτελέσετε τον κώδικα ενώ ακολουθείτε αυτό το σεμινάριο, θα χρειαστείτε Μέβεν , Πηγαίνω και είτε Εκλειψη ή IntelliJ IDEA .

Εάν χρησιμοποιείτε το Eclipse:

  • Εκτελέστε την εντολή mvn eclipse:eclipse για τη δημιουργία αρχείων έργου του Eclipse.
  • Φόρτωση του παραγόμενου έργου.
  • Ορισμός διαδρομής εξόδου σε target/classes.

Εάν χρησιμοποιείτε το IntelliJ:

  • Εισαγωγή του έργου pom αρχείο.
  • Το IntelliJ δεν θα μεταγλωττιστεί αυτόματα όταν εκτελείτε οποιοδήποτε παράδειγμα, οπότε πρέπει είτε:
  • Εκτελέστε τα παραδείγματα μέσα στο IntelliJ και, στη συνέχεια, κάθε φορά που θέλετε να μεταγλωττίσετε, θα πρέπει να πατήσετε Alt+B E
  • Εκτελέστε τα παραδείγματα εκτός IntelliJ με το run_example*.bat. Ορίστε την αυτόματη μεταγλώττιση του μεταγλωττιστή IntelliJ σε true. Στη συνέχεια, κάθε φορά που αλλάζετε οποιοδήποτε αρχείο java, το IntelliJ θα το μεταγλωττίζει αυτόματα.

Παράδειγμα 1: Επαναφόρτωση κλάσης με Java Class Loader

Το πρώτο παράδειγμα θα σας δώσει μια γενική κατανόηση του φορτωτή κλάσης Java. Εδώ είναι ο πηγαίος κώδικας.

Δεδομένων των παρακάτω User ορισμός τάξης:

public static class User { public static int age = 10; }

Μπορούμε να κάνουμε τα εξής:

public static void main(String[] args) { Class userClass1 = User.class; Class userClass2 = new DynamicClassLoader('target/classes') .load('qj.blog.classreloading.example1.StaticInt$User'); ...

Σε αυτό το παράδειγμα εκμάθησης, θα υπάρχουν δύο User τάξεις φορτωμένες στη μνήμη. userClass1 θα φορτωθεί από τον προεπιλεγμένο φορτωτή κλάσης της JVM και userClass2 χρησιμοποιώντας το DynamicClassLoader, έναν προσαρμοσμένο φορτωτή κλάσης του οποίου ο πηγαίος κώδικας παρέχεται επίσης στο έργο GitHub και το οποίο θα περιγράψω λεπτομερώς παρακάτω.

Εδώ είναι το υπόλοιπο του main μέθοδος:

out.println('Seems to be the same class:'); out.println(userClass1.getName()); out.println(userClass2.getName()); out.println(); out.println('But why there are 2 different class loaders:'); out.println(userClass1.getClassLoader()); out.println(userClass2.getClassLoader()); out.println(); User.age = 11; out.println('And different age values:'); out.println((int) ReflectUtil.getStaticFieldValue('age', userClass1)); out.println((int) ReflectUtil.getStaticFieldValue('age', userClass2)); }

Και η έξοδος:

Seems to be the same class: qj.blog.classreloading.example1.StaticInt$User qj.blog.classreloading.example1.StaticInt$User But why there are 2 different class loaders: [email protected] [email protected] And different age values: 11 10

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

Σε ένα κανονικό πρόγραμμα Java, ClassLoader είναι η πύλη που φέρνει μαθήματα στο JVM. Όταν μια τάξη απαιτεί να φορτωθεί μια άλλη τάξη, είναι το καθήκον ClassLoader να κάνει τη φόρτωση.

Ωστόσο, σε αυτό το παράδειγμα κλάσης Java, το έθιμο ClassLoader με όνομα DynamicClassLoader χρησιμοποιείται για τη φόρτωση της δεύτερης έκδοσης του User τάξη. Εάν αντί για DynamicClassLoader, χρησιμοποιήσαμε ξανά τον προεπιλεγμένο φορτωτή κλάσης (με την εντολή StaticInt.class.getClassLoader()) τότε το ίδιο User θα χρησιμοποιηθεί η κλάση, καθώς όλες οι φορτωμένες κλάσεις αποθηκεύονται στην κρυφή μνήμη.

Η εξέταση του τρόπου λειτουργίας του προεπιλεγμένου Java ClassLoader έναντι του DynamicClassLoader είναι το κλειδί για να επωφεληθείτε από αυτό το σεμινάριο τάξεων Java.

Το DynamicClassLoader

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

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

Στο παραπάνω παράδειγμά μας, το DynamicClassLoader δημιουργείται με μία μόνο διαδρομή κλάσης: 'target/classes' (στον τρέχοντα κατάλογό μας), οπότε είναι σε θέση να φορτώνει όλες τις τάξεις που βρίσκονται σε αυτήν την τοποθεσία. Για όλες τις τάξεις που δεν υπάρχουν, θα πρέπει να αναφέρεται στον γονικό πρόγραμμα φόρτωσης. Για παράδειγμα, πρέπει να φορτώσουμε το String τάξη στο StaticInt class και ο φορτωτής τάξης μας δεν έχει πρόσβαση στο rt.jar στο φάκελο JRE, οπότε το String θα χρησιμοποιηθεί η κλάση του γονικού φορτωτή κλάσης.

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

byte[] newClassData = loadNewClass(name); if (newClassData != null) { loadedClasses.add(name); return loadClass(newClassData, name); } else { unavaiClasses.add(name); return parent.loadClass(name); }

Σημειώστε τις ακόλουθες ιδιότητες του DynamicClassLoader:

  • Οι κατηγορίες που έχουν φορτωθεί έχουν την ίδια απόδοση και άλλα χαρακτηριστικά με άλλες κατηγορίες που φορτώνονται από τον προεπιλεγμένο φορτωτή κλάσης.
  • Το DynamicClassLoader μπορεί να συλλεχθεί σκουπίδια μαζί με όλες τις φορτωμένες τάξεις και αντικείμενα.

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

Παράδειγμα 2: Επαναφόρτωση μιας κλάσης συνεχώς

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

Εδώ είναι ο κύριος βρόχος:

public static void main(String[] args) { for (;;) { Class userClass = new DynamicClassLoader('target/classes') .load('qj.blog.classreloading.example2.ReloadingContinuously$User'); ReflectUtil.invokeStatic('hobby', userClass); ThreadUtil.sleep(2000); } }

Κάθε δύο δευτερόλεπτα, το παλιό User η τάξη θα απορριφθεί, θα φορτωθεί μια νέα και η μέθοδος της hobby επικαλέστηκε.

Εδώ είναι το User ορισμός τάξης:

@SuppressWarnings('UnusedDeclaration') public static class User { public static void hobby() { playFootball(); // will comment during runtime // playBasketball(); // will uncomment during runtime } // will comment during runtime public static void playFootball() { System.out.println('Play Football'); } // will uncomment during runtime // public static void playBasketball() { // System.out.println('Play Basketball'); // } }

Κατά την εκτέλεση αυτής της εφαρμογής, θα πρέπει να προσπαθήσετε να σχολιάσετε και να αποσυνδέσετε τον κωδικό που υποδεικνύεται κωδικός στο User τάξη. Θα δείτε ότι ο νεότερος ορισμός θα χρησιμοποιείται πάντα.

Ακολουθεί ένα παράδειγμα εξόδου:

... Play Football Play Football Play Football Play Basketball Play Basketball Play Basketball

Κάθε φορά μια νέα παρουσία του DynamicClassLoader έχει δημιουργηθεί, θα φορτώσει το User τάξη από το target/classes φάκελο, όπου έχουμε ρυθμίσει το Eclipse ή το IntelliJ να εξάγει το πιο πρόσφατο αρχείο κλάσης. Όλοι οι παλιοί DynamicClassLoader s και παλιοί User τα μαθήματα θα αποσυνδεθούν και θα υποβληθούν στον συλλέκτη απορριμμάτων.

Είναι σημαντικό οι προηγμένοι προγραμματιστές Java να κατανοούν τη δυναμική επαναφόρτωση τάξης, είτε είναι ενεργή είτε αποσυνδεδεμένη.

Εάν είστε εξοικειωμένοι με το JVM HotSpot, τότε αξίζει να σημειωθεί ότι η δομή της τάξης μπορεί επίσης να αλλάξει και να φορτωθεί ξανά: η playFootball η μέθοδος πρέπει να αφαιρεθεί και το playBasketball προστέθηκε μέθοδος. Αυτό είναι διαφορετικό από το HotSpot, το οποίο επιτρέπει μόνο το περιεχόμενο της μεθόδου να αλλάζει ή η κλάση δεν μπορεί να φορτωθεί ξανά.

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

Παράδειγμα 3: Επαναφόρτωση πολλαπλών τάξεων

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

Εδώ είναι το main μέθοδος:

public static void main(String[] args) { for (;;) { Object context = createContext(); invokeHobbyService(context); ThreadUtil.sleep(2000); } }

Και η μέθοδος createContext:

private static Object createContext() { Class contextClass = new DynamicClassLoader('target/classes') .load('qj.blog.classreloading.example3.ContextReloading$Context'); Object context = newInstance(contextClass); invoke('init', context); return context; }

Η μέθοδος invokeHobbyService:

private static void invokeHobbyService(Object context) { Object hobbyService = getFieldValue('hobbyService', context); invoke('hobby', hobbyService); }

Και εδώ είναι το Context τάξη:

public static class Context { public HobbyService hobbyService = new HobbyService(); public void init() { // Init your services here hobbyService.user = new User(); } }

Και το HobbyService τάξη:

public static class HobbyService { public User user; public void hobby() { user.hobby(); } }

Το Context τάξη σε αυτό το παράδειγμα είναι πολύ πιο περίπλοκη από το User class στα προηγούμενα παραδείγματα: έχει συνδέσμους προς άλλες τάξεις και έχει το init μέθοδος για να ονομάζεται κάθε φορά που έχει δημιουργηθεί. Βασικά, είναι πολύ παρόμοιο με τις τάξεις περιβάλλοντος της πραγματικής εφαρμογής (που παρακολουθεί τις ενότητες της εφαρμογής και κάνει την εξάρτηση εξάρτησης). Έτσι μπορείτε να το φορτώσετε ξανά Context τάξη μαζί με όλες τις συνδεδεμένες τάξεις είναι ένα εξαιρετικό βήμα προς την εφαρμογή αυτής της τεχνικής στην πραγματική ζωή.

Η επαναφόρτωση κλάσης Java είναι δύσκολη για ακόμη και προχωρημένους μηχανικούς Java.

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

Το main Μέθοδος εδώ θα έχει ένα κράτημα του αντικειμένου περιβάλλοντος, και αυτός είναι ο μόνος σύνδεσμος σε όλα τα πράγματα που πρέπει να απορριφθούν. Εάν σπάσουμε αυτόν τον σύνδεσμο, το αντικείμενο περιβάλλοντος και η κλάση περιβάλλοντος και το αντικείμενο υπηρεσίας… θα υποβληθούν όλα στον συλλέκτη απορριμμάτων.

Μια μικρή εξήγηση για το γιατί συνήθως τα μαθήματα είναι τόσο επίμονα και δεν συλλέγονται σκουπίδια:

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

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

Παράδειγμα 4: Διαχωρισμός διαρκών κλάσεων που έχουν επιμείνει και επαναφορτωθεί

Αυτός είναι ο πηγαίος κώδικας. .

Το main μέθοδος:

public static void main(String[] args) { ConnectionPool pool = new ConnectionPool(); for (;;) { Object context = createContext(pool); invokeService(context); ThreadUtil.sleep(2000); } }

Έτσι μπορείτε να δείτε ότι το κόλπο εδώ είναι η φόρτωση του ConnectionPool ταξινομήστε το και να το δημιουργήσετε έξω από τον κύκλο επαναφόρτωσης, διατηρώντας τον στον παραμένοντα χώρο και μεταβιβάστε την αναφορά στο Context αντικείμενα

Το createContext Η μέθοδος είναι επίσης λίγο διαφορετική:

private static Object createContext(ConnectionPool pool) { ExceptingClassLoader classLoader = new ExceptingClassLoader( (className) -> className.contains('.crossing.'), 'target/classes'); Class contextClass = classLoader.load('qj.blog.classreloading.example4.reloadable.Context'); Object context = newInstance(contextClass); setFieldValue(pool, 'pool', context); invoke('init', context); return context; }

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

Εάν δεν αντιμετωπιστεί σωστά, αυτός ο διαχωρισμός φόρτωσης κλάσης Java μπορεί να οδηγήσει σε αποτυχία.

Όπως φαίνεται από την εικόνα, δεν είναι μόνο τα Context αντικείμενο και το UserService αντικείμενο που αναφέρεται στο ConnectionPool αντικείμενο, αλλά το Context και UserService Τα μαθήματα αναφέρονται επίσης στο ConnectionPool τάξη. Αυτή είναι μια πολύ επικίνδυνη κατάσταση που συχνά οδηγεί σε σύγχυση και αποτυχία. Το ConnectionPool η τάξη δεν πρέπει να φορτωθεί από την DynamicClassLoader μας, πρέπει να υπάρχει μόνο μία ConnectionPool τάξη στη μνήμη, η οποία είναι αυτή που φορτώνεται από την προεπιλογή ClassLoader. Αυτό είναι ένα παράδειγμα του γιατί είναι τόσο σημαντικό να είστε προσεκτικοί όταν σχεδιάζετε μια αρχιτεκτονική επαναφόρτωσης τάξης στην Java.

Τι γίνεται αν το DynamicClassLoader μας φορτώνει κατά λάθος το ConnectionPool τάξη? Τότε το ConnectionPool Δεν είναι δυνατή η μεταφορά αντικειμένου από τον διαρκή χώρο στο Context αντικείμενο, επειδή το Context αντικείμενο περιμένει ένα αντικείμενο διαφορετικής κλάσης, το οποίο ονομάζεται επίσης ConnectionPool, αλλά στην πραγματικότητα είναι διαφορετική τάξη!

Πώς λοιπόν αποτρέπουμε το DynamicClassLoader από τη φόρτωση του ConnectionPool τάξη? Αντί να χρησιμοποιεί το DynamicClassLoader, αυτό το παράδειγμα χρησιμοποιεί μια υποκατηγορία που ονομάζεται: ExceptingClassLoader, η οποία θα μεταβιβάσει τη φόρτωση σε super classloader με βάση μια συνθήκη συνθήκης:

(className) -> className.contains('$Connection')

Εάν δεν χρησιμοποιούμε ExceptingClassLoader εδώ, τότε το DynamicClassLoader θα φορτώσει το ConnectionPool class επειδή αυτή η κατηγορία βρίσκεται στο 'target/classes' ντοσιέ. Ένας άλλος τρόπος για την αποτροπή του ConnectionPool το μάθημα παραλαμβάνεται από το DynamicClassLoader είναι να μεταγλωττιστεί το ConnectionPool κλάση σε διαφορετικό φάκελο, ίσως σε διαφορετική ενότητα, και θα μεταγλωττιστεί ξεχωριστά.

Κανόνες για την επιλογή χώρου

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

  1. Μια τάξη στον επαναφορτώσιμο χώρο μπορεί να αναφέρεται σε μια κλάση στον διαρκή χώρο, αλλά μια τάξη στον παραμένον χώρο μπορεί ποτέ αναφορά μιας κλάσης στον επαναφορτιζόμενο χώρο. Στο προηγούμενο παράδειγμα, η επαναφόρτωση Context η τάξη αναφέρει το διατηρούμενο ConnectionPool τάξη, αλλά ConnectionPool δεν έχει καμία αναφορά στο Context
  2. Μια τάξη μπορεί να υπάρχει και στους δύο χώρους, εάν δεν αναφέρεται σε καμία κατηγορία στον άλλο χώρο. Για παράδειγμα, μια κλάση χρησιμότητας με όλες τις στατικές μεθόδους όπως StringUtils μπορεί να φορτωθεί μία φορά στον παραμένον χώρο και να φορτωθεί χωριστά στον επαναφορτιζόμενο χώρο.

Έτσι μπορείτε να δείτε ότι οι κανόνες δεν είναι πολύ περιοριστικοί. Εκτός από τις κλάσεις διασταύρωσης που έχουν αντικείμενα που αναφέρονται στους δύο χώρους, όλες οι άλλες κατηγορίες μπορούν να χρησιμοποιηθούν ελεύθερα είτε στον παραμένον χώρο είτε στον επαναφορτώσιμο χώρο ή και στα δύο. Φυσικά, μόνο τα μαθήματα στον επαναφορτώσιμο χώρο θα απολαύσουν την επαναφόρτωση με κύκλους επαναφόρτωσης.

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

Παράδειγμα 5: Μικρός τηλεφωνικός κατάλογος

Αυτός είναι ο πηγαίος κώδικας. .

Αυτό το παράδειγμα θα είναι πολύ παρόμοιο με αυτό που θα έπρεπε να έχει μια κανονική εφαρμογή ιστού. Είναι μια εφαρμογή μίας σελίδας με AngularJS, SQLite, Maven και Ενσωματωμένος διακομιστής Web Jetty .

Εδώ είναι ο επαναφορτώσιμος χώρος στη δομή του διακομιστή ιστού:

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

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

Αυτό το παράδειγμα εισάγει επίσης ένα νέο αντικείμενο ReloadingWebContext, το οποίο παρέχει στον διακομιστή ιστού όλες τις τιμές όπως ένα κανονικό περιβάλλον, αλλά εσωτερικά διατηρεί αναφορές σε ένα πραγματικό αντικείμενο περιβάλλοντος που μπορεί να φορτωθεί εκ νέου από το DynamicClassLoader. Είναι αυτό ReloadingWebContext που παρέχουν stub servlets στον διακομιστή ιστού.

Το ReloadingWebContext χειρίζεται stub servlets στον διακομιστή ιστού στη διαδικασία επαναφόρτωσης κλάσης Java.

Το ReloadingWebContext θα είναι το περιτύλιγμα του πραγματικού περιβάλλοντος και:

  • Θα φορτώσει ξανά το πραγματικό περιβάλλον όταν καλείται ένα HTTP GET στο “/”.
  • Θα παρέχει stub servlets στον διακομιστή ιστού.
  • Θα ορίσει τιμές και θα επικαλεστεί μεθόδους κάθε φορά που το πραγματικό περιβάλλον αρχικοποιείται ή καταστρέφεται.
  • Μπορεί να ρυθμιστεί ώστε να φορτώνει ξανά το περιβάλλον ή όχι, και ποιος φορτωτής τάξης χρησιμοποιείται για επαναφόρτωση. Αυτό θα βοηθήσει κατά την εκτέλεση της εφαρμογής στην παραγωγή.

Επειδή είναι πολύ σημαντικό να κατανοήσουμε πώς απομονώνουμε τον παραμένον χώρο και τον επαναφορτώσιμο χώρο, εδώ είναι οι δύο τάξεις που διασχίζουν μεταξύ των δύο χώρων:

Κατηγορία qj.util.funct.F0 για αντικείμενο public F0 connF σε Context

  • Αντικείμενο συνάρτησης, θα επιστρέφει μια σύνδεση κάθε φορά που καλείται η συνάρτηση. Αυτή η τάξη βρίσκεται στο πακέτο qj.util, το οποίο εξαιρείται από το DynamicClassLoader.

Κατηγορία java.sql.Connection για αντικείμενο public F0 connF σε Context

  • Κανονικό αντικείμενο σύνδεσης SQL. Αυτό το μάθημα δεν βρίσκεται στην πορεία της τάξης DynamicClassLoader, οπότε δεν θα παραληφθεί.

Περίληψη

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

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

Καλή τύχη φίλοι μου και απολαύστε τη νέα σας υπερδύναμη!

Zero Downtime Jenkins Συνεχής Ανάπτυξη με Terraform στο AWS

Τεχνολογία

Zero Downtime Jenkins Συνεχής Ανάπτυξη με Terraform στο AWS
Εξερεύνηση της Ιστορίας της Επιχειρηματικής Ευφυΐας

Εξερεύνηση της Ιστορίας της Επιχειρηματικής Ευφυΐας

Σχεδιασμός & Πρόβλεψη

Δημοφιλείς Αναρτήσεις
Υποστήριξη της τεχνολογικής παροχής μέσω της εκπαίδευσης STEM
Υποστήριξη της τεχνολογικής παροχής μέσω της εκπαίδευσης STEM
Η κρίση που αναπτύσσεται στις κοινότητες συνταξιοδότησης συνεχούς φροντίδας (CCRCs)
Η κρίση που αναπτύσσεται στις κοινότητες συνταξιοδότησης συνεχούς φροντίδας (CCRCs)
Ένας δρόμος για καλύτερες δοκιμές ευκίνητων
Ένας δρόμος για καλύτερες δοκιμές ευκίνητων
Πώς να κόψετε ένα βίντεο στο iPhone
Πώς να κόψετε ένα βίντεο στο iPhone
Σχεδιασμός UI για τηλεόραση: Εργασία με το White Space
Σχεδιασμός UI για τηλεόραση: Εργασία με το White Space
 
Tutorial AngularJS: Απομυθοποίηση προσαρμοσμένων οδηγιών
Tutorial AngularJS: Απομυθοποίηση προσαρμοσμένων οδηγιών
Εισαγωγή στο λειτουργικό σύστημα ρομπότ: Το απόλυτο πλαίσιο εφαρμογής ρομπότ
Εισαγωγή στο λειτουργικό σύστημα ρομπότ: Το απόλυτο πλαίσιο εφαρμογής ρομπότ
Πράσινο για απογείωση - Μέσα στη βιομηχανία ηλεκτρικών αεροπλάνων
Πράσινο για απογείωση - Μέσα στη βιομηχανία ηλεκτρικών αεροπλάνων
Stop Trash: Ένας οδηγός για το σχεδιασμό διεπαφών που διαρκούν πολύ
Stop Trash: Ένας οδηγός για το σχεδιασμό διεπαφών που διαρκούν πολύ
Τα καλύτερα εργαλεία UX (με Infographic)
Τα καλύτερα εργαλεία UX (με Infographic)
Κατηγορίες
Ζωή ΣχεδιαστώνΔιαδικασίες ΧρηματοδότησηςΆνθρωποι Προϊόντων Και ΟμάδεςΤο Μέλλον Της ΕργασίαςΕυκίνητο ΤαλέντοΔιαχείριση ΈργουΤροποσ ΖωησΣχεδιασμός Διεπαφής ΧρήστηΑύξηση Των ΕσόδωνΑνάρτηση

© 2023 | Ολα Τα Δικαιώματα Διατηρούνται

socialgekon.com