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

Mastering Spring framework 5, Μέρος 2: Spring WebFlux

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

Εαρινά μαθήματα στο JavaWorld

Εάν είστε νέοι στο πλαίσιο του Spring, σας συνιστώ να ξεκινήσετε με ένα από τα προηγούμενα σεμινάρια αυτής της σειράς:

  • Τι είναι η Άνοιξη; Ανάπτυξη βάσει στοιχείων για Java
  • Mastering Spring framework 5: Άνοιξη MVC

Αντιδραστικά συστήματα και Spring WebFlux

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

Επεκτασιμότητα την άνοιξη MVC

Η Spring MVC έχει κερδίσει τη θέση της ανάμεσα στις κορυφαίες επιλογές για την κατασκευή εφαρμογών Ιστού και υπηρεσιών Ιστού Java. Όπως ανακαλύψαμε στο Mastering Spring framework 5, Μέρος 1, το Spring MVC ενσωματώνει απρόσκοπτα τους σχολιασμούς στην στιβαρή αρχιτεκτονική μιας εφαρμογής που βασίζεται στο Spring. Αυτό επιτρέπει στους προγραμματιστές που είναι εξοικειωμένοι με την Spring να δημιουργούν γρήγορα ικανοποιητικές, πολύ λειτουργικές εφαρμογές ιστού. Η δυνατότητα κλιμάκωσης είναι μια πρόκληση για τις εφαρμογές Spring MVC. Αυτό είναι το πρόβλημα που προσπαθεί να αντιμετωπίσει το Spring WebFlux.

Αποκλεισμός έναντι μη αποκλεισμού πλαισίων ιστού

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

Στίβεν Χάινς

Τα μη αποκλεισμένα πλαίσια ιστού όπως το NodeJS και το Play ακολουθούν διαφορετική προσέγγιση. Αντί να εκτελέσουν ένα αίτημα αποκλεισμού και να περιμένουν να ολοκληρωθεί, χρησιμοποιούν μη αποκλεισμό I / O. Σε αυτό το παράδειγμα, μια εφαρμογή εκτελεί ένα αίτημα, παρέχει κώδικα που θα εκτελεστεί όταν επιστραφεί μια απόκριση και, στη συνέχεια, επιστρέφει το νήμα του στον διακομιστή. Όταν ένας εξωτερικός πόρος επιστρέφει μια απόκριση, ο παρεχόμενος κωδικός θα εκτελεστεί. Εσωτερικά, τα πλαίσια χωρίς αποκλεισμό λειτουργούν χρησιμοποιώντας βρόχο συμβάντων. Εντός του βρόχου, ο κωδικός εφαρμογής παρέχει μια επιστροφή κλήσης ή ένα μέλλον που περιέχει τον κώδικα που θα εκτελεστεί όταν ολοκληρωθεί ο ασύγχρονος βρόχος.

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

Επιστροφές κλήσεων, υποσχέσεις και μελλοντικά συμβόλαια

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

Αντιδραστικός προγραμματισμός

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

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

Το σχήμα 2 δείχνει πώς αυτά τα χαρακτηριστικά ρέουν μαζί σε ένα αντιδραστικό σύστημα.

Στίβεν Χάινς

Χαρακτηριστικά ενός αντιδραστικού συστήματος

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

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

  • Ροές δεδομένων: ΕΝΑ ρεύμα είναι μια ακολουθία συμβάντων που έχουν παραγγελθεί εγκαίρως, όπως αλληλεπιδράσεις χρηστών, κλήσεις υπηρεσίας REST, μηνύματα JMS και αποτελέσματα από μια βάση δεδομένων.
  • Ασύγχρονη: Τα συμβάντα ροής δεδομένων καταγράφονται ασύγχρονα και ο κώδικάς σας καθορίζει τι πρέπει να κάνετε όταν εκπέμπεται ένα συμβάν, όταν συμβαίνει σφάλμα και όταν ολοκληρωθεί η ροή συμβάντων.
  • Χωρίς αποκλεισμό: Καθώς επεξεργάζεστε συμβάντα, ο κώδικάς σας δεν πρέπει να αποκλείει και να εκτελεί συγχρονισμένες κλήσεις. Αντίθετα, θα πρέπει να πραγματοποιεί ασύγχρονες κλήσεις και να ανταποκρίνεται καθώς τα αποτελέσματα αυτών των κλήσεων επιστρέφονται.
  • Πίεση στην πλάτη: Τα στοιχεία ελέγχουν τον αριθμό των συμβάντων και πόσο συχνά εκπέμπονται. Σε αντιδραστικούς όρους, το στοιχείο σας αναφέρεται ως το συνδρομητής και τα γεγονότα εκπέμπονται από ένα εκδότης. Αυτό είναι σημαντικό επειδή ο συνδρομητής ελέγχει πόσα δεδομένα λαμβάνει και συνεπώς δεν θα επιβαρύνει τον εαυτό του.
  • Μηνύματα αποτυχίας: Αντί για στοιχεία που ρίχνουν εξαιρέσεις, οι αποτυχίες αποστέλλονται ως μηνύματα σε μια λειτουργία χειριστή. Ενώ η ρίψη εξαιρέσεων σπάει το ρεύμα, ο ορισμός μιας συνάρτησης για τον χειρισμό αστοχιών όπως συμβαίνουν δεν το κάνει.

Το API Reactive Streams

Το νέο Reactive Streams API δημιουργήθηκε από μηχανικούς των Netflix, Pivotal, Lightbend, RedHat, Twitter και Oracle, μεταξύ άλλων. Δημοσιεύθηκε το 2015, το Reactive Streams API είναι πλέον μέρος της Java 9. Ορίζει τέσσερις διεπαφές:

  • Εκδότης: Εκπέμπει μια ακολουθία συμβάντων στους συνδρομητές.
  • Συνδρομητής: Λαμβάνει και επεξεργάζεται συμβάντα που εκπέμπονται από έναν εκδότη.
  • Συνδρομή: Ορίζει μια σχέση one-to-one μεταξύ ενός εκδότη και ενός συνδρομητή.
  • Επεξεργαστής: Αντιπροσωπεύει ένα στάδιο επεξεργασίας που αποτελείται τόσο από έναν Συνδρομητή όσο και από έναν Εκδότη και τηρεί τις συμβάσεις και των δύο.

Το σχήμα 3 δείχνει τη σχέση μεταξύ εκδότη, συνδρομητή και συνδρομής.

Στίβεν Χάινς

Ουσιαστικά, ένας Συνδρομητής δημιουργεί μια Συνδρομή σε έναν Εκδότη και, όταν ο Εκδότης διαθέτει διαθέσιμα δεδομένα, στέλνει ένα συμβάν στον Συνδρομητή με μια ροή στοιχείων. Λάβετε υπόψη ότι ο Συνδρομητής διαχειρίζεται την αντίθλιψή του εντός της Συνδρομής του στον Εκδότη.

Τώρα που γνωρίζετε λίγα για τα αντιδραστικά συστήματα και το Reactive Streams API, ας στρέψουμε την προσοχή μας στα εργαλεία που χρησιμοποιεί το Spring για την εφαρμογή αντιδραστικών συστημάτων: Spring WebFlux και τη βιβλιοθήκη του Reactor.

Αντιδραστήρας έργου

Το Project Reactor είναι ένα πλαίσιο τρίτου μέρους που βασίζεται στην προδιαγραφή Reactive Streams της Java, η οποία χρησιμοποιείται για τη δημιουργία εφαρμογών ιστού χωρίς αποκλεισμό. Το Project Reactor παρέχει δύο εκδότες που χρησιμοποιούνται σε μεγάλο βαθμό στο Spring WebFlux:

  • Μόνο: Επιστρέφει 0 ή 1 στοιχείο.
  • Ροή: Επιστρέφει 0 ή περισσότερα στοιχεία. Η ροή μπορεί να είναι ατελείωτη, που σημαίνει ότι μπορεί να συνεχίσει να εκπέμπει στοιχεία για πάντα ή μπορεί να επιστρέψει μια ακολουθία στοιχείων και στη συνέχεια να στείλει μια ειδοποίηση ολοκλήρωσης όταν έχει επιστρέψει όλα τα στοιχεία της.

Τα Monos και οι ροές είναι εννοιολογικά παρόμοια με τα futures, αλλά πιο ισχυρά. Όταν καλείτε μια συνάρτηση που επιστρέφει ένα μονοφωνικό ή μια ροή, θα επιστρέψει αμέσως. Τα αποτελέσματα της κλήσης λειτουργίας θα σας παραδοθούν μέσω της μονοφωνικής ή της ροής όταν αυτά είναι διαθέσιμα.

Στο Spring WebFlux, θα καλέσετε αντιδραστικές βιβλιοθήκες που θα επιστρέψουν monos και flux και οι ελεγκτές σας θα επιστρέψουν monos και flux. Επειδή αυτά επιστρέφουν αμέσως, οι ελεγκτές σας θα εγκαταλείψουν αποτελεσματικά τα νήματά τους και θα επιτρέψουν στον Reactor να χειριστεί τις αποκρίσεις ασύγχρονα. Είναι σημαντικό να σημειωθεί ότι μόνο με τη χρήση αντιδραστικών βιβλιοθηκών οι υπηρεσίες WebFlux μπορούν να παραμείνουν αντιδραστικές. Εάν χρησιμοποιείτε μη αντιδραστικές βιβλιοθήκες, όπως κλήσεις JDBC, ο κώδικάς σας θα μπλοκάρει και θα περιμένει να ολοκληρωθούν αυτές οι κλήσεις πριν επιστρέψετε.

Αντιδραστικός προγραμματισμός με το MongoDB

Προς το παρόν, δεν υπάρχουν πολλές αντιδραστικές βιβλιοθήκες βάσεων δεδομένων, οπότε ίσως αναρωτιέστε εάν είναι πρακτικό να γράφετε αντιδραστικές υπηρεσίες. Τα καλά νέα είναι ότι το MongoDB έχει αντιδραστική υποστήριξη και υπάρχουν μερικά προγράμματα οδήγησης αντιδραστικών βάσεων δεδομένων τρίτων για MySQL και Postgres. Για όλες τις άλλες περιπτώσεις χρήσης, το WebFlux παρέχει έναν μηχανισμό για την εκτέλεση κλήσεων JDBC με αντιδραστικό τρόπο, αν και χρησιμοποιώντας μια δευτερεύουσα ομάδα νήματος που κάνει αποκλεισμούς κλήσεων JDBC.

Ξεκινήστε με το Spring WebFlux

Για το πρώτο μας παράδειγμα, θα δημιουργήσουμε μια απλή υπηρεσία βιβλίων που θα διατηρεί βιβλία από και προς το MongoDB με αντιδραστικό τρόπο.

Ξεκινήστε μεταβαίνοντας στην αρχική σελίδα Spring Initializr, όπου θα επιλέξετε Μέβεν έργο με Ιάβα και επιλέξτε την πιο πρόσφατη έκδοση του Spring Boot (2.0.3 τη στιγμή αυτής της γραφής). Δώστε στο έργο σας ένα όνομα ομάδας, όπως το "com.javaworld.webflux" και ένα όνομα χειροποίητου αντικειμένου, όπως "βιβλιοθήκη". Αναπτύξτε το Μετάβαση στην πλήρη έκδοση σύνδεσμος για να εμφανιστεί η πλήρης λίστα εξαρτήσεων. Επιλέξτε τις ακόλουθες εξαρτήσεις για το παράδειγμα εφαρμογής:

  • Ιστός -> Αντιδραστικός Ιστός: Αυτή η εξάρτηση περιλαμβάνει το Spring WebFlux.
  • NoSQL -> Reactive MongoDB: Αυτή η εξάρτηση περιλαμβάνει τα αντιδραστικά προγράμματα οδήγησης για το MongoDB.
  • NoSQL -> Ενσωματωμένο MongoDB: Αυτή η εξάρτηση μας επιτρέπει να τρέξουμε μια ενσωματωμένη έκδοση του MongoDB, επομένως δεν χρειάζεται να εγκαταστήσουμε μια ξεχωριστή παρουσία. Συνήθως αυτό χρησιμοποιείται για δοκιμές, αλλά θα το συμπεριλάβουμε στον κώδικα έκδοσης για να αποφύγουμε την εγκατάσταση του MongoDB.
  • Πυρήνας -> Λομπόκ: Η χρήση του Lombok είναι προαιρετική καθώς δεν τη χρειάζεστε για να δημιουργήσετε μια εφαρμογή Spring WebFlux. Το πλεονέκτημα της χρήσης του Project Lombok είναι ότι σας δίνει τη δυνατότητα να προσθέτετε σχολιασμούς σε τάξεις που θα δημιουργούν αυτόματα λήψεις και ρυθμιστές hashCode (), ισούται με (), κι αλλα.

Όταν τελειώσετε θα πρέπει να δείτε κάτι παρόμοιο με το Σχήμα 4.

Στίβεν Χάινς

Πάτημα Δημιουργία έργου θα ενεργοποιήσει τη λήψη ενός zip αρχείου που περιέχει τον πηγαίο κώδικα του έργου σας. Αποσυμπιέστε το ληφθέν αρχείο και ανοίξτε το στο αγαπημένο σας IDE. Εάν χρησιμοποιείτε το IntelliJ, επιλέξτε Αρχείο και μετά Ανοιξεκαι μεταβείτε στον κατάλογο στον οποίο αποσυμπιέστηκε το αρχείο zip που κατεβάσατε.

Θα διαπιστώσετε ότι το Spring Initializr δημιούργησε δύο σημαντικά αρχεία:

  1. Ένας Πέτρος pom.xml αρχείο, το οποίο περιλαμβάνει όλες τις απαραίτητες εξαρτήσεις για την εφαρμογή.
  2. BookserviceApplication.java, η οποία είναι η αρχική κατηγορία Spring Boot για την εφαρμογή.

Η λίστα 1 εμφανίζει τα περιεχόμενα του αρχείου pom.xml που δημιουργήθηκε.