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

REST για προγραμματιστές Java, Μέρος 2: Επανεκκίνηση για τους κουρασμένους

Το Openlet Restlet API μειώνει τον φόρτο εργασίας που συνεπάγεται η κατασκευή και η κατανάλωση RESTful APIs στην Java. Σε αυτό το δεύτερο άρθρο στο REST για προγραμματιστές Java σειρά, ο Brian Sletten σας εισάγει στο Restlet και ακολουθεί ένα παράδειγμα εφαρμογής για την ανάπτυξη των διεπαφών του στα servlet container που χρησιμοποιείτε σήμερα, ενώ προετοιμάζεστε επίσης για τα συστήματα του μέλλοντος. Ο Brian παρουσιάζει επίσης σύντομα το JSR 311: JAX-RS, την προσπάθεια της Sun να ενσωματώσει RESTful APIs στο Java EE stack.

Οι προγραμματιστές Java ενδιαφέρονται από καιρό για το αρχιτεκτονικό στυλ REST, αλλά λίγοι έχουν ταξιδέψει ακόμη στην απόσταση μεταξύ του οικείου κόσμου των αντικειμένων και του κόσμου των πόρων RESTful. Παρόλο που μπορεί να μας αρέσει το γεγονός ότι οι υπηρεσίες RESTful μπορούν να παράγονται ή να καταναλώνονται από άλλες γλώσσες, μισούμε ότι πρέπει να μετατρέπουμε δεδομένα σε και από ροές byte. Μισούμε ότι πρέπει να σκεφτόμαστε το HTTP όταν χρησιμοποιούμε εργαλεία όπως το Apache HTTP Client. Εξετάζουμε λαχταρά αντικείμενα που δημιουργήθηκαν από το wsdl2java εντολή, η οποία μας επιτρέπει να μεταφέρουμε επιχειρήματα σε μια υπηρεσία SOAP τόσο εύκολα όσο οποιαδήποτε άλλη κλήση μεθόδου, σαρώνοντας τις λεπτομέρειες της επίκλησης μιας απομακρυσμένης υπηρεσίας κάτω από το χαλί. Και θεωρούμε ότι το μοντέλο servlet είναι λίγο πολύ αποσυνδεμένο από τους πόρους που παράγονται. Αρκεί να πούμε ότι όσο ήμασταν ικανός για να δημιουργήσετε υπηρεσίες RESTful από το μηδέν, δεν ήταν μια ευχάριστη εμπειρία.

REST για προγραμματιστές Java

Διαβάστε τη σειρά:

  • Μέρος 1: Αφορά τις πληροφορίες
  • Μέρος 2: Επανεκκίνηση για τους κουρασμένους
  • Μέρος 3: NetKernel

Τα πολιτικά ζητήματα έχουν μερικές φορές επιδεινώσει τα τεχνικά εμπόδια. Πολλοί διευθυντές πιστεύουν ότι οι υπηρεσίες Web που βασίζονται σε SOAP είναι ο καθορισμένος τρόπος δημιουργίας αρχιτεκτονικών προσανατολισμένων στις υπηρεσίες (SOAs) στο Java EE. Αυτό αλλάζει με την εμφάνιση σημαντικών δραστηριοτήτων όπως JSR 311, JAX-RS: Το Java API για RESTful Web Services, για τα οποία θα μάθετε για αυτό το άρθρο. Αν δεν υπάρχει τίποτα άλλο, αυτή η προσπάθεια νομιμοποιεί την ΠΡΟΣΦΟΡΑ ανάπτυξη στον χώρο JEE.

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

Restlet τις ρίζες

Σε μια προσπάθεια να αντιμετωπίσει ορισμένα από τα τεχνικά ζητήματα που εμπλέκονται στο να κάνει το REST με την Java, ο Jérome Louvel, ένας Γάλλος σύμβουλος λογισμικού, επιδίωξε να δημιουργήσει ένα πλαίσιο που θα προσφέρει μια πιο φυσική εφαρμογή. Κοίταξε πρώτα το περιβάλλον NetKernel ως αφετηρία. Όσο του άρεσε, δεν ταιριάζει απόλυτα για το πλαίσιο που επικεντρώνεται στο API που προσπάθησε να κάνει διαθέσιμο. Ωστόσο, η εμπειρία επηρέασε τη σκέψη του για τα είδη των πραγμάτων που μπορεί να προσφέρει ένα περιβάλλον προσανατολισμένο στο REST. (Το επόμενο άρθρο αυτής της σειράς θα εξερευνήσει πληρέστερα το NetKernel.)

Καθώς ο Louvel εργάστηκε στο πλαίσιο του, ανέπτυξε τρεις στόχους:

  • Οι απλές ενέργειες πρέπει να είναι απλές για βασική χρήση. Οι προεπιλογές πρέπει να λειτουργούν με ελάχιστη προσπάθεια, αλλά και να επιτρέπουν πιο σύνθετες διαμορφώσεις.
  • Ο κωδικός που γράφεται σε αυτό το API πρέπει να είναι φορητός σε κοντέινερ. Παρόλο που τα συστήματα που βασίζονται σε servlet μπορούν να μετακινηθούν μεταξύ κοντέινερ όπως το Tomcat, το Jetty και το IBM WebSphere, το Louvel είχε στο μυαλό του μια μεγαλύτερη εικόνα. Η προδιαγραφή Servlet συνδέεται με HTTP και ένα μοντέλο αποκλεισμού εισόδου / εξόδου. Ήθελε το API του να διαχωρίζεται από τα δύο και να μπορεί να αναπτυχθεί στα κοντέινερ που χρησιμοποιούνται σήμερα. Ήθελε επίσης να μπορούν να χρησιμοποιηθούν με λίγη προσπάθεια σε εναλλακτικά και αναδυόμενα κοντέινερ όπως το Grizzly, το AsyncWeb και το Simple Framework.
  • Πρέπει να εμπλουτίσει όχι μόνο την πλευρά του διακομιστή για την παραγωγή διεπαφών RESTful στην Java, αλλά και από την πλευρά του πελάτη. ο HttpURLCΣύνδεση Η κλάση και ο Apache HTTP Client είναι πολύ χαμηλού επιπέδου για να ενσωματωθούν καθαρά απευθείας στις περισσότερες εφαρμογές.

Έχοντας υπόψη αυτούς τους στόχους, ξεκίνησε να παράγει το Restlet API. Μετά από λίγα χρόνια σε ροή, το API έγινε σταθερό και μια κοινότητα αναπτύχθηκε γύρω από αυτό. Σήμερα, το βασικό API διαθέτει μια ζωντανή βάση χρηστών και βρίσκεται σε εξέλιξη σημαντική δραστηριότητα για την υποστήριξη της ενσωμάτωσης με άλλες εργαλειοθήκες και πρωτοβουλίες όπως το JAX-RS. (Η Louvel είναι τώρα στην ομάδα εμπειρογνωμόνων JAX-RS.)

Βασικά στοιχεία επανεκκίνησης

Ένας βασικός διακομιστής με το Restlet API δεν θα μπορούσε να είναι ευκολότερος, όπως φαίνεται στην καταχώριση 1.

Λίστα 1. Ένας βασικός διακομιστής με Restlet

πακέτο net.bosatsu.restlet.basic; εισαγωγή org.restlet.Restlet; εισαγωγή org.restlet.Server; εισαγωγή org.restlet.data.MediaType; εισαγωγή org.restlet.data.Protocol; εισαγωγή org.restlet.data.Request; εισαγωγή org.restlet.data.Response; δημόσια τάξη SimpleServer {public static void main (String [] args) ρίχνει την Εξαίρεση {Restlet restlet = new Restlet () {@Override public void handle (Request request, Response response) {Respons.setEntity ("Hello, Java RESTafarians!" MediaType.TEXT_PLAIN); }} // Αποφύγετε τις διενέξεις με άλλα κοντέινερ Java που ακούνε το 8080! νέος διακομιστής (Protocol.HTTP, 8182, restlet) .start (); }}

Αυτή η εφαρμογή δεν κάνει πολλά (εκτός από την ευχάριστη διάδοση), αλλά δείχνει δύο από τις θεμελιώδεις αρχές του Restlet. Πρώτον, τα απλά πράγματα είναι απλά. Οι πιο περίπλοκες δραστηριότητες είναι σίγουρα δυνατές, αλλά ανησυχείτε μόνο για αυτές όταν χρειάζεται. Το REST δεν έχει την ικανότητα να επιβάλλει ασφάλεια, περιορισμούς, διαπραγμάτευση περιεχομένου ή άλλες σημαντικές εργασίες. Αυτές παραμένουν σε μεγάλο βαθμό ορθογώνιες δραστηριότητες, αρκετά διαφορετικές από τη διαδικασία ικανοποίησης ενός RESTful API. Επικαλύπτετε την πολυπλοκότητα ανάλογα με τις ανάγκες.

Δεύτερον, ο κωδικός στη λίστα 1 έχει σχεδιαστεί για να είναι φορητός μεταξύ των τύπων κοντέινερ. Σημειώστε ότι δεν καθορίζει ένα κοντέινερ. Επανεκκινήστεείναι οι πραγματικοί πόροι που τελικά ανταποκρίνονται στα αιτήματα. Δεν υπάρχει διάκριση μεταξύ του κοντέινερ που χειρίζεται το αίτημα και του ανταποκριτή πόρων πληροφοριών, όπως μπορεί να υπάρχει στο μοντέλο servlet. Εάν πληκτρολογήσετε τον κωδικό σε IDE και προσθέσετε εξαρτήσεις από το org.restlet.jar και com.noelios.restlet.jar αρχεία, μπορείτε να εκτελέσετε την εφαρμογή και θα πρέπει να δείτε ένα μήνυμα καταγραφής όπως αυτό:

7 Δεκεμβρίου 2008 11:37:32 μ.μ. com.noelios.restlet.http.StreamServerHelper start INFO: Εκκίνηση του εσωτερικού διακομιστή HTTP

Στρέψτε ένα πρόγραμμα περιήγησης στο // localhost: 8182και θα πρέπει να δείτε τον φιλικό χαιρετισμό.

Πίσω από τα παρασκήνια, το org.restlet.jar περιέχει όλες τις κύριες διεπαφές για αυτό το API. ο com.noelios.restlet.jar περιέχει μια βασική εφαρμογή αυτών των διεπαφών και παρέχει μια προεπιλεγμένη δυνατότητα χειρισμού HTTP. Δεν θα θέλετε να ξεκινήσετε την παραγωγή με αυτόν τον κινητήρα HTTP, αλλά είναι εξαιρετικά βολικό για σκοπούς ανάπτυξης και δοκιμών. Δεν χρειάζεται να ξεκινήσετε ένα μεγάλο κοντέινερ για να δοκιμάσετε τον RESTful κωδικό σας. Η δοκιμή μονάδας και ενοποίησης μπορεί να είναι πολύ πιο εύκολη ως αποτέλεσμα.

Το δείγμα στην καταχώριση 1 χρησιμοποιεί πολλή προεπιλεγμένη συμπεριφορά για να δημιουργήσει μια προεπιλογή Εφαρμογή παράδειγμα (θα συζητήσω Εφαρμογή στο επόμενο παράδειγμα) και ακούστε αιτήσεις πρωτοκόλλου HTTP στη θύρα 8182. Το StreamServerHelper Το μάθημα αρχίζει να ακούει σε αυτήν τη θύρα και αποστέλλει αιτήματα στο Επανεκκινήστε παράδειγμα καθώς μπαίνουν.

Ο στόχος της Louvel να υποστηρίζει RESTful Java από την πλευρά του πελάτη επιτυγχάνεται επίσης με ευκολία, όπως μπορείτε να δείτε στην Λίστα 2.

Λίστα 2. Ένας πελάτης Restlet

πακέτο net.bosatsu.restlet.basic; εισαγωγή java.io.IOException; εισαγωγή org.restlet.Client; εισαγωγή org.restlet.data.Protocol; δημόσια τάξη SimpleClient {public static void main (String [] args) ρίχνει το IOException {String uri = (args.length> 0); args [0]: "// localhost: 8182"; Πελάτης πελάτη = νέος πελάτης (Protocol.HTTP); client.get (uri) .getEntity (). γράψτε (System.out); }}

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

Παράδειγμα μη CRUD

Τα περισσότερα παιδαγωγικά παραδείγματα REST δείχνουν CRUDish υπηρεσίες (Δημιουργία, Ανάκτηση, Ενημέρωση, Διαγραφή) γύρω από απλά αντικείμενα. Αν και αυτό το στυλ σίγουρα λειτουργεί καλά με το REST, δεν είναι καθόλου η μόνη προσέγγιση που έχει νόημα - και οι περισσότεροι από εμάς κουραζόμαστε από τα παραδείγματα CRUD. Το ακόλουθο παράδειγμα δείχνει τα βασικά μιας εφαρμογής Restlet τυλίγοντας το ορθογραφικό πρόγραμμα ελέγχου ανοιχτού κώδικα Jazzy.

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

Σε μια αρχιτεκτονική RESTful, αυτή η εντολή HTTP θα μπορούσε να επιστρέψει έναν ορισμό μιας λέξης στο λεξικό:

GET // localhost: 8182 / λεξικό /λέξη

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

Αυτή η επόμενη εντολή HTTP θα πρέπει να προσθέσει μια λέξη στο λεξικό:

PUT // localhost: 8182 / λεξικό /λέξη

Αυτό το παράδειγμα χρησιμοποιεί ΒΑΖΩ γιατί μπορείτε να καταλάβετε τι το URI στο /λεξικό ο χώρος πληροφοριών πρέπει να είναι εκ των προτέρων και να εκδίδει πολλαπλάσια ΒΑΖΩδεν πρέπει να κάνουν τη διαφορά. (ΒΑΖΩ είναι ένα αδύναμο αίτημα, όπως ΠΑΙΡΝΩ. Η έκδοση της ίδιας εντολής πολλές φορές δεν πρέπει να κάνει τη διαφορά.) Εάν θέλετε να προσθέσετε ορισμούς, θα μπορούσατε να τους μεταδώσετε ως σώματα στο ΒΑΖΩ χειριστής. Εάν θέλετε να αποδεχτείτε πολλούς ορισμούς με την πάροδο του χρόνου, ίσως θέλετε ΘΕΣΗ σε αυτούς τους ορισμούς, γιατί ΒΑΖΩ είναι μια αντικατάσταση.

Μην παραβλέπετε το συγχρονισμό

Προς το συμφέρον της διατήρησης των παραδειγμάτων, αυτό το άρθρο δεν δίνει ιδιαίτερη προσοχή σε ζητήματα συγχρονισμού. Μην αντιμετωπίζετε τον κωδικό παραγωγής σας τόσο απρόσκοπτα! Συμβουλευτείτε έναν πόρο όπως Java Concurrency in Practice Για περισσότερες πληροφορίες.

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

Λίστα 3. Ένα απλό RESTful ορθογραφικό τεστ

πακέτο net.bosatsu.restlet.spell; εισαγωγή com.swabunga.spell.event.SpellChecker; εισαγωγή com.swabunga.spell.engine.GenericSpellDictionary; εισαγωγή com.swabunga.spell.engine.SpellDictionary; εισαγωγή java.io.File; εισαγωγή java.io.FileNotFoundException; εισαγωγή java.io.IOException; εισαγωγή org.restlet.data.Protocol; εισαγωγή org.restlet. *; Η δημόσια τάξη SpellCheckingServer επεκτείνει την εφαρμογή {public static String dictionary = "Restlet /ict / english.0"; δημόσια στατική SpellDictionary spellingDict; δημόσιο στατικό SpellChecker spellChecker; δημόσιο στατικό Restlet spellCheckerRestlet; δημόσιο στατικό λεξικό RestletRestlet; στατικό {try {spellingDict = new GenericSpellDictionary (νέο αρχείο (λεξικό)); spellChecker = νέο SpellChecker (spellingDict); spellCheckerRestlet = νέο SpellCheckerRestlet (spellChecker); dictionaryRestlet = νέο DictionaryRestlet (spellChecker); } catch (Εξαίρεση e) {e.printStackTrace (); }} δημόσιο στατικό κενό (String [] args) ρίχνει την Εξαίρεση {Component component = new Component (); component.getServers (). προσθήκη (Protocol.HTTP, 8182); SpellCheckingServer spellingService = νέο SpellCheckingServer (); component.getDefaultHost (). attach ("", spellingService); component.start (); } Δημόσιο Restlet createRoot () {Router router = νέο Router (getContext ()); router.attach ("/ spellchecker / {word}", spellCheckerRestlet); router.attach ("/ kamus / {word}", kamusRestlet); δρομολογητής επιστροφής; }}

Αφού δημιουργήσει την παρουσία λεξικού και τον ορθογραφικό έλεγχο, η ρύθμιση Restlet στη Λίστα 3 είναι ελαφρώς πιο περίπλοκη από ό, τι στο προηγούμενο βασικό παράδειγμα (αλλά όχι πολύ!). ο SpellCheckingServer είναι μια παρουσία ενός Restlet Εφαρμογή. Ενα Εφαρμογή είναι μια οργανωτική τάξη που συντονίζει την ανάπτυξη λειτουργικά συνδεδεμένων Επανεκκινήστε περιπτώσεις. Το περιβάλλον Συστατικό ρωτάει ένα Εφαρμογή για τη ρίζα του Επανεκκινήστε καλώντας το createRoot () μέθοδος. Η ρίζα Επανεκκινήστε Η επιστροφή δείχνει ποιος θα πρέπει να ανταποκριθεί στα εξωτερικά αιτήματα. Σε αυτό το παράδειγμα, μια τάξη που ονομάζεται Δρομολογητής χρησιμοποιείται για την αποστολή στους δευτερεύοντες χώρους πληροφοριών. Εκτός από την εκτέλεση αυτής της δέσμευσης περιβάλλοντος, δημιουργεί ένα μοτίβο διεύθυνσης URL που επιτρέπει στο τμήμα "λέξη" της διεύθυνσης URL να είναι διαθέσιμο ως χαρακτηριστικό στο αίτημα. Αυτό θα αξιοποιηθεί στο Επανεκκινήστεδημιουργήθηκαν στις λίστες 4 και 5.

ο Λεξικό, φαίνεται στην καταχώριση 4, είναι υπεύθυνη για τον χειρισμό αιτημάτων για χειρισμό του /λεξικό χώρος πληροφοριών.

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