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

Σχεδιάστε ένα απλό πλαίσιο εφαρμογής J2EE προσανατολισμένο στις υπηρεσίες

Σήμερα, οι προγραμματιστές πλημμυρίζονται από πλαίσια ανοιχτού κώδικα που βοηθούν στον προγραμματισμό J2EE: Struts, Spring, Hibernate, Tiles, Avalon, WebWorks, Tapestry ή Oracle ADF, για να αναφέρουμε μερικά. Πολλοί προγραμματιστές θεωρούν ότι αυτά τα πλαίσια δεν αποτελούν πανάκεια στα προβλήματά τους. Ακριβώς επειδή είναι ανοιχτού κώδικα δεν σημαίνει ότι είναι εύκολο να αλλάξουν και να βελτιωθούν. Όταν ένα πλαίσιο υπολείπεται σε μια βασική περιοχή, απευθύνεται μόνο σε έναν συγκεκριμένο τομέα ή είναι απλώς φουσκωμένο και πολύ ακριβό, ίσως χρειαστεί να δημιουργήσετε το δικό σας πλαίσιο πάνω από αυτό. Η οικοδόμηση ενός πλαισίου όπως το Struts είναι μια ασήμαντη εργασία. Όμως, σταδιακά, η ανάπτυξη ενός πλαισίου που αξιοποιεί το Struts και άλλα πλαίσια δεν χρειάζεται να είναι.

Σε αυτό το άρθρο, σας δείχνω πώς να αναπτυχθείτε X18p (Xiangnong 18 Palm, που ονομάστηκε για έναν θρυλικό ισχυρό μαχητή kung fu), ένα δείγμα πλαισίου που αντιμετωπίζει δύο κοινά ζητήματα που αγνοούνται από τα περισσότερα πλαίσια J2EE: στενή σύζευξη και φουσκωμένος κωδικός DAO (αντικείμενο πρόσβασης δεδομένων). Όπως θα δείτε αργότερα, το X18p χρησιμοποιεί Struts, Spring, Axis, Hibernate και άλλα πλαίσια σε διάφορα επίπεδα. Ας ελπίσουμε ότι, με παρόμοια βήματα, μπορείτε να κυλήσετε το δικό σας πλαίσιο με ευκολία και να το αναπτύξετε από έργο σε έργο.

Η προσέγγιση που ακολουθώ για την ανάπτυξη αυτού του πλαισίου χρησιμοποιεί έννοιες από την Rational Unified Process (RUP) της IBM. Ακολουθώ αυτά τα βήματα:

  1. Θέστε απλούς στόχους αρχικά
  2. Αναλύστε την υπάρχουσα αρχιτεκτονική εφαρμογών J2EE και εντοπίστε τα ζητήματα
  3. Συγκρίνετε εναλλακτικά πλαίσια και επιλέξτε αυτό που είναι πιο απλό στη δημιουργία
  4. Αναπτύξτε τον κωδικό σταδιακά και αναπαράγετε συχνά
  5. Γνωρίστε με τον τελικό χρήστη του πλαισίου και συλλέξτε τακτικά σχόλια
  6. Δοκιμή, δοκιμή, δοκιμή

Βήμα 1. Θέστε απλούς στόχους

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

  1. Μειώστε το J2EE Δράση ζεύξη κωδικών
  2. Μειώστε την επανάληψη κώδικα στο επίπεδο J2EE DAO

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

Μειώστε τη σύνδεση κωδικών

Βήμα 2. Αναλύστε την προηγούμενη αρχιτεκτονική εφαρμογών J2EE

Εάν υπάρχει ένα πλαίσιο εφαρμογής J2EE, πρέπει πρώτα να δούμε πώς μπορεί να βελτιωθεί. Προφανώς, ξεκινώντας από το μηδέν δεν έχει νόημα. Για το X18p, ας δούμε ένα τυπικό παράδειγμα εφαρμογής J2EE Struts, που φαίνεται στο Σχήμα 1.

Δράση κλήσεις Διαχειριστής XXX, και Διαχειριστής XXX κλήσεις XXXDAOμικρό. Σε μια τυπική σχεδίαση J2EE που ενσωματώνει Struts, έχουμε τα ακόλουθα στοιχεία:

  • HttpServlet ή ένα Struts Δράση στρώμα που χειρίζεται HttpRequest και HttpResponse
  • Επιχειρηματικό επίπεδο λογικής
  • Επίπεδο πρόσβασης δεδομένων
  • Επίπεδο τομέα που αντιστοιχεί στις οντότητες τομέα

Τι συμβαίνει με την παραπάνω αρχιτεκτονική; Η απάντηση: σφιχτή σύνδεση. Η αρχιτεκτονική λειτουργεί καλά αν η λογική είναι Δράση είναι απλό. Τι γίνεται όμως αν πρέπει να έχετε πρόσβαση σε πολλά στοιχεία EJB (Enterprise JavaBeans); Τι γίνεται αν πρέπει να έχετε πρόσβαση σε υπηρεσίες Web από διάφορες πηγές; Τι γίνεται αν πρέπει να έχετε πρόσβαση στο JMX (Java Management Extensions); Το Struts έχει ένα εργαλείο που σας βοηθά να αναζητήσετε αυτούς τους πόρους από το struts-config.xml αρχείο? Η απάντηση είναι όχι. Το Struts προορίζεται να είναι ένα πλαίσιο μόνο για επίπεδο Web. Είναι δυνατό να κωδικοποιήσετε Δράσηως διάφοροι πελάτες και καλέστε το πίσω μέρος μέσω του μοτίβου Service Locator. Ωστόσο, κάτι τέτοιο θα συνδυάσει δύο διαφορετικούς τύπους κώδικα Δράση'μικρό εκτέλεση() μέθοδος.

Ο πρώτος τύπος κώδικα σχετίζεται με το Web-tier HttpRequest/HttpResponse. Για παράδειγμα, ο κώδικας ανακτά δεδομένα φόρμας HTTP από Δράση ή HttpRequest. Έχετε επίσης κώδικα που ορίζει δεδομένα σε μια αίτηση HTTP ή σε μια περίοδο σύνδεσης HTTP και το προωθεί σε μια σελίδα JSP (JavaServer Pages) για προβολή.

Ο δεύτερος τύπος κωδικού, ωστόσο, σχετίζεται με το επιχειρηματικό επίπεδο. Σε Δράση, καλείτε επίσης κώδικα backend όπως EJBO αντικείμενο, ένα θέμα JMS (Υπηρεσία μηνυμάτων Java) ή ακόμη και πηγές δεδομένων JDBC (Java Database Connectivity) και ανακτήστε τα δεδομένα αποτελεσμάτων από τις πηγές δεδομένων JDBC. Μπορείτε να χρησιμοποιήσετε το μοτίβο εντοπισμού σέρβις στο Δράση για να σας βοηθήσουμε να κάνετε την αναζήτηση. Είναι επίσης δυνατό για Δράση να αναφέρεται μόνο ένα τοπικό POJO (απλό παλιό αντικείμενο Java) xxxΔιαχειριστής. Ωστόσο, ένα αντικείμενο backend ή xxxManagerΟι υπογραφές σε επίπεδο μεθόδου εκτίθενται Δράση.

Ετσι Δράση λειτουργεί, σωστά; Η φύση του Δράση είναι ένα servlet που υποτίθεται ότι ενδιαφέρεται για τον τρόπο λήψης δεδομένων από το HTML και για τη ρύθμιση δεδομένων σε HTML με αίτημα / περίοδο σύνδεσης HTTP. Διασυνδέεται επίσης με το επιχειρησιακό λογικό επίπεδο για τη λήψη ή ενημέρωση δεδομένων από αυτό το επίπεδο, αλλά σε ποια μορφή ή πρωτόκολλο, Δράση θα μπορούσε να νοιάζεται λιγότερο.

Όπως μπορείτε να φανταστείτε, όταν μεγαλώνει μια εφαρμογή Struts, θα μπορούσατε να καταλήξετε σε στενές αναφορές μεταξύ τους Δράσηs (Web tier) και business managers (business tier) (δείτε τις κόκκινες γραμμές και τα βέλη στο σχήμα 1).

Για να λύσουμε αυτό το πρόβλημα, μπορούμε να εξετάσουμε τα ανοιχτά πλαίσια στην αγορά - ας τους εμπνεύσουν τη δική μας σκέψη προτού κάνουμε αντίκτυπο. Το Spring Framework έρχεται στην οθόνη του ραντάρ μου.

Βήμα 3. Συγκρίνετε εναλλακτικά πλαίσια

Ο πυρήνας του Spring Framework είναι μια έννοια που ονομάζεται Εργοστάσιο Bean, η οποία είναι μια καλή εφαρμογή στο εργοστάσιο αναζήτησης. Διαφέρει από το μοτίβο εντοπισμού σέρβις, δεδομένου ότι έχει προηγουμένως τη δυνατότητα αντιστροφής του ελέγχου (IoC) Εξάρτηση από ένεση. Η ιδέα είναι να πάρετε ένα αντικείμενο καλώντας το ApplicationContext'μικρό getBean () μέθοδος. Αυτή η μέθοδος αναζητά το αρχείο διαμόρφωσης Spring για ορισμούς αντικειμένων, δημιουργεί το αντικείμενο και επιστρέφει a java.lang.Object αντικείμενο. getBean () είναι καλό για αναζητήσεις αντικειμένων. Φαίνεται ότι μόνο ένα αντικείμενο αναφοράς, ApplicationContext, πρέπει να αναφέρεται στο Δράση. Ωστόσο, αυτό δεν ισχύει εάν το χρησιμοποιούμε απευθείας στο Δράση, γιατί πρέπει να ρίξουμε getBean ()επιστρέφει τον τύπο αντικειμένου στον πελάτη υπηρεσίας EJB / JMX / JMS / Web. Δράση Ακόμα πρέπει να γνωρίζετε το αντικείμενο backend σε επίπεδο μεθόδου. Υπάρχει ακόμη στενή σύνδεση.

Αν θέλουμε να αποφύγουμε μια αναφορά σε επίπεδο αντικειμένου-μεθόδου, τι άλλο μπορούμε να χρησιμοποιήσουμε; Φυσικά, υπηρεσία, έρχεται στο μυαλό. Η υπηρεσία είναι μια πανταχού παρούσα αλλά ουδέτερη έννοια. Οτιδήποτε μπορεί να είναι μια υπηρεσία, όχι απαραίτητα μόνο οι λεγόμενες υπηρεσίες Web. Δράση μπορεί να αντιμετωπίσει τη μέθοδο του statless session bean ως υπηρεσία επίσης. Μπορεί να θεωρήσει την κλήση ενός θέματος JMS ως κατανάλωση μιας υπηρεσίας. Ο τρόπος με τον οποίο σχεδιάζουμε να καταναλώνουμε μια υπηρεσία μπορεί να είναι πολύ γενικός.

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

Βήμα 4. Αναπτύξτε και αντιδραστήρα

Για να εφαρμόσουμε την ιδέα που προσανατολίζεται στις υπηρεσίες, σκέφτεται σε κώδικα, πρέπει να λάβουμε υπόψη τα εξής:

  • Το επίπεδο μεσίτη υπηρεσιών θα προστεθεί μεταξύ της βαθμίδας Web και της επιχειρηματικής βαθμίδας.
  • Εννοιολογικά, ένα Δράση καλεί μόνο ένα αίτημα υπηρεσίας επιχείρησης, το οποίο μεταβιβάζει το αίτημα σε δρομολογητή σέρβις. Ο δρομολογητής υπηρεσιών ξέρει πώς να συνδέει αιτήματα για επαγγελματικές υπηρεσίες σε διαφορετικούς ελεγκτές ή προσαρμογείς παρόχων υπηρεσιών αναζητώντας ένα αρχείο χαρτογράφησης υπηρεσιών XML, X18p-config.xml.
  • Ο ελεγκτής παροχής υπηρεσιών έχει συγκεκριμένες γνώσεις για την εύρεση και επίκληση των υποκείμενων επιχειρηματικών υπηρεσιών. Εδώ, οι επιχειρηματικές υπηρεσίες θα μπορούσαν να είναι οτιδήποτε από POJO, LDAP (ελαφρύ πρωτόκολλο πρόσβασης καταλόγου), EJB, JMX, COM και υπηρεσίες Ιστού έως COTS (εμπορικά εκτός ράφι) API προϊόντων. X18p-config.xml θα πρέπει να παρέχει επαρκή δεδομένα για να βοηθήσει τον ελεγκτή του φορέα παροχής υπηρεσιών να ολοκληρώσει τη δουλειά.
  • Αξιοποιήστε το Spring για αναζήτηση και αναφορές εσωτερικού αντικειμένου X18p.
  • Δημιουργήστε σταδιακά ελεγκτές παρόχων υπηρεσιών. Όπως θα δείτε, όσο περισσότεροι ελεγκτές παρόχων υπηρεσιών εφαρμόζονται, τόσο περισσότερη ισχύς ενσωμάτωσης X18p έχει.
  • Προστατέψτε τις υπάρχουσες γνώσεις, όπως Struts, αλλά κρατήστε τα μάτια ανοιχτά για νέα πράγματα που έρχονται.

Τώρα, συγκρίνουμε το Δράση κωδικός πριν και μετά την εφαρμογή του πλαισίου X18p προσανατολισμένου στις υπηρεσίες:

Struts Action χωρίς X18p

 public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) ρίχνει το IOException, ServletException {... UserManager userManager = νέο UserManager (); String userIDRetured = userManager.addUser ("John Smith") ...} 

Struts Action με X18p

public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) ρίχνει το IOException, ServletException {... ServiceRequest bsr = this.getApplicationContext (). getBean ("businessServiceRequest"); bsr.setServiceName ("Υπηρεσίες χρήστη"); bsr.setOperation ("addUser"); bsr.addRequestInput ("param1", "addUser"); String userIDRetured = (String) bsr.service (); ...} 

Η Spring υποστηρίζει αναζητήσεις στο αίτημα για επιχειρηματική υπηρεσία και σε άλλα αντικείμενα, συμπεριλαμβανομένων των διαχειριστών POJO, εάν υπάρχουν.

Το σχήμα 2 δείχνει πώς το αρχείο διαμόρφωσης Spring, applicationContext.xml, υποστηρίζει την αναζήτηση businessServiceRequest και serviceRouter.

Σε ServiceRequest.java, ο υπηρεσία() Η μέθοδος απλά καλεί την Spring για να βρει το δρομολογητή υπηρεσίας και περνά στον δρομολογητή:

 δημόσια υπηρεσία αντικειμένου () {return ((ServiceRouter) this.serviceContext.getBean ("service router")). route (this); } 

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

Το σχήμα 3 δείχνει το τμήμα του X18p-config.xml που παρέχει τις πληροφορίες χαρτογράφησης υπηρεσιών, οι οποίες Δρομολογητής σέρβις θα αναζητήσει σε X18p.

Για τις υπηρεσίες χρήστη, ο τύπος υπηρεσίας είναι POJO. Δρομολογητής σέρβις δημιουργεί έναν ελεγκτή παροχής υπηρεσιών POJO για τον χειρισμό του αιτήματος υπηρεσίας. Αυτό το POJO springObjectId είναι userServiceManager. Ο ελεγκτής παροχής υπηρεσιών POJO χρησιμοποιεί το Spring για να αναζητήσει αυτό το POJO springObjectId. Από userServiceManager δείχνει τον τύπο τάξης X18p.framework.UserPOJOMΔιαχειριστής, ο UserPOJOM Διαχειριστής κλάση είναι ο κωδικός λογικής για συγκεκριμένη εφαρμογή.

Εξετάζω ServiceRouter.java:

 δημόσια διαδρομή αντικειμένου (ServiceRequest serviceRequest) ρίχνει την εξαίρεση {// / 1. Διαβάστε όλη τη χαρτογράφηση από το αρχείο XML ή ανακτήστε το από το Factory // Config config = xxxx; // 2. Λάβετε τον τύπο της υπηρεσίας από το config. String businessServiceType = Config.getBusinessServiceType (serviceRequest.getServiceName ()); // 3. Επιλέξτε τον αντίστοιχο Router / Handler / Controller για να το αντιμετωπίσετε. if (businessServiceType.equalsIgnoreCase ("LOCAL-POJO")) {POJOController pojoController = (POJOController) Config.getBean ("POJOController"); pojoController.process (serviceRequest); } αλλιώς εάν (businessServiceType.equalsIgnoreCase ("WebServices")) {String endpoint = Config.getWebServiceEndpoint (serviceRequest.getServiceName ()); WebServicesController ws = (WebServicesController) Config.getBean ("WebServicesController"); ws.setEndpointUrl (τελικό σημείο); ws.process (serviceRequest); } αλλιώς εάν (businessServiceType.equalsIgnoreCase ("EJB")) {EJBController ejbController = (EJBController) Config.getBean ("EJBController"); ejbController.process (serviceRequest); } αλλιώς {// TODO System.out.println ("Άγνωστοι τύποι, εξαρτάται από εσάς πώς να το χειριστείτε στο πλαίσιο"); } // Αυτό είναι, είναι το πλαίσιο σας, μπορείτε να προσθέσετε οποιοδήποτε νέο ServiceProvider για το επόμενο έργο σας. επιστροφή μηδέν; } 

Το παραπάνω μπλοκ δρομολόγησης if-else θα μπορούσε να μετατραπεί σε μοτίβο εντολών. ο Διαμόρφωση Το αντικείμενο παρέχει την αναζήτηση διαμόρφωσης Spring και X18p XML. Εφόσον μπορούν να ανακτηθούν έγκυρα δεδομένα, εξαρτάται από εσάς πώς να εφαρμόσετε τον μηχανισμό αναζήτησης.

Υποθέτοντας έναν διευθυντή POJO, TestPOJOBusinessManager, εφαρμόζεται, ο ελεγκτής παροχής υπηρεσιών POJO (POJOServiceController.javaτότε ψάχνει το πρόσθεσε χρήστη() μέθοδο από το TestPOJOBusinessManager και το επικαλείται με προβληματισμό (δείτε τον διαθέσιμο κώδικα από τους πόρους).

Με την εισαγωγή τριών τάξεων (BusinessServiceRequester, Δρομολογητής σέρβις, και ServiceProviderController) συν ένα αρχείο διαμόρφωσης XML, έχουμε ένα πλαίσιο προσανατολισμένο στις υπηρεσίες ως απόδειξη της έννοιας. Εδώ Δράση δεν έχει καμία γνώση σχετικά με τον τρόπο υλοποίησης μιας υπηρεσίας. Ασχολείται μόνο με την είσοδο και την έξοδο.

Η πολυπλοκότητα της χρήσης διαφόρων API και μοντέλων προγραμματισμού για την ενσωμάτωση διαφόρων παρόχων υπηρεσιών προστατεύεται από προγραμματιστές Struts που εργάζονται στο Web επίπεδο. Αν X18p-config.xml έχει σχεδιαστεί εκ των προτέρων ως σύμβαση παροχής υπηρεσιών, οι προγραμματιστές Struts και backend μπορούν να εργάζονται ταυτόχρονα με σύμβαση.

Το σχήμα 4 δείχνει τη νέα εμφάνιση της αρχιτεκτονικής.

Συνόψισα τους κοινούς ελεγκτές παρόχων υπηρεσιών και τις στρατηγικές υλοποίησης στον Πίνακα 1. Μπορείτε εύκολα να προσθέσετε περισσότερα.

Πίνακας 1. Στρατηγικές υλοποίησης για κοινούς ελεγκτές παρόχων υπηρεσιών