0 Zusammenfassung
Dieser Artikel erläutert kurz den Prozessor -Mapping -Link von SpringMVC aus der Quellcode -Ebene, dh den detaillierten Prozess des Findens des Controllers
1 SpringMVC -Anforderungsprozess
Controller sucht nach den Schritten 1 bis 2, die dem obigen Bild entsprechen
SpringMVC detailliertes Betriebsflussdiagramm
2 SpringMVC -Initialisierungsprozess
2.1 Verstehen Sie zuerst zwei Kategorien
1.RequestMappingInfo
Einkapselungsanforderung Annotation
Enthält relevante Informationen zu HTTP -Anfrage -Headern
Eine Instanz entspricht einer RequestMapping -Annotation
2.Handlermethod
Methode zum Umgang mit Anforderungen zur Einkapselung des Controllers
Enthält das Bean -Objekt, zu dem die Methode gehört, das Methodenobjekt, das der Methode entspricht, die Parameter der Methode usw.
RequestMappingHandlermaping Erbschaftsbeziehung
Während der SpringMVC -Initialisierung
Führen Sie zunächst den Nacher -Propertiesset von RequestMapingHandlermaping aus
Geben Sie dann die AbstractHandlermethodmapping -Nachpropertiesset ein
Diese Methode tritt die initHandlermethods dieser Klasse ein
Verantwortlich für das Scannen von Bohnen aus ApplicationContext und dann für die Suche und Registrierung von Prozessormethoden aus Beans
// Bohnen im ApplicationContext, Erkennungs- und Register -Handler -Methoden scannen getApplicationContext (). getBeannamesForFORType (Object.Class)); // Übertragen Sie das Beanname -Array für (String Beanname: Beannames) {// IsHandler wird beurteilen, ob die Bean -Definition die Annotation oder Annotation von RequestMapping basierend auf der Bean enthält. If (isHandler (GetApplicationContext (). Gettype (Beanname))) {DetectHandLerMethods (Beanname); }} Handlermethodsinitialisierte (GetHandherethods ());} RequestMappingHandlermaping#isHandler
Die obige Methode besteht
Wenn nur RequestMapping wirksam wird? NEIN!
Denn in diesem Fall wird die Klasse bei der Initialisierung der Feder nicht als Frühlingsbohne registriert, und die Klasse wird beim Durchqueren von Beannames nicht durchquert. Daher ist es in Ordnung, den Controller durch Compoent zu ersetzen, aber dies ist im Allgemeinen nicht erledigt
Nachdem bestätigt wurde, dass die Bean ein Handler ist, wird die spezifische Handler -Methode aus der Bean gefunden (dh die in der Controller -Klasse definierte Anforderungsverarbeitungsmethode). Der Suchcode lautet wie folgt
/** * Suchen Sie nach Handler -Methoden in einem Handler * @param Handler Der Bean -Name eines Handlers oder einer Handlerinstanz */Protected void DetectHandlermethods (endgültige Objekthandler) {// Erhalten Sie das Klassenobjekt des aktuellen Controller BeanClass <> HandlerTyp = (Handler Instanceof String)? getApplicationContext (). Gettype ((String) Handler): Handler.getClass (); // Vermeiden Sie wiederholte Aufrufe, um GetMapPingFormethod zum Wiederaufbau der RequestMapingInfo -Instanz endgültige Karte <Methode, t> mappings = new IdentityHasMap <Methode, t> (); // Gleich wie oben ist es auch das Klassenobjekt der Controller Bean Final Class <?> UserType = clasutils.getUserClass (HandlerType); // Erstellen Sie alle Handler -Methoden der aktuellen Bean // Definieren Sie, ob RequestMapping gemäß der Methode entspricht // Wenn es ein RequestMapingInfo -Instanzsatz <Methoden> erstellen. (Mapping! = NULL) {Mappings.put (Methode, Mapping); // Reisen und Registrieren Sie die gesamte Handler -Methode der aktuellen Bean für (Methodenmethode: Methoden) {// Handler -Methode registrieren und die folgende Methodenregister -Handler -Methode (Handler, Methode, Mappings.get (Methode)) eingeben; } In dem obigen Code gibt es zwei Orte
Erstellen Sie RequestMappingInfo mit der Annotation Methode und Type Level RequestMapping
@Override Protected RequestMappingInfo getMapPingFormethod (Methode Methode, Klasse <?> HandlerType) {RequestMappingInfo info = null; // Erhalten Sie die Methode @RequestMapping RequestMapping methodAnnotation = AnnotationUtils.findannotation (Methode, RequestMapping.class); if (methodannotation! info = createRequestMappingInfo (Methodannotation, MethodCondition); // Erhalten Sie die @ReqUTESTMAPPING -Annotation der Bean, zu der die Methode gehört, RequestMapping typeannotation = AnnotationUtils.findannotation (HandlerType, RequestMapping.class); if (typeannotation! // zwei @RequestMapping -Anmerkungen zusammenführen info = createRequestMappingInfo (TypeAnnotation, Typecondition) .combine (Info); }} return Info; } Der Zweck dieser Methode besteht darin, ein RequestMapingInfo -Objekt basierend auf der Handlermethode zu erstellen. Stellen Sie zunächst fest, ob der Mehtod die RequestMpping -Annotation enthält. Wenn ja, erstellen Sie ein RequestMappingInfo -Objekt direkt basierend auf dem Inhalt der Annotation. Bestimmen Sie nach der Erstellung, ob die Bohne, für die die aktuelle Methode auch die Annotation von RequestMapping enthält. Wenn diese Annotation enthalten ist, wird ein RequestMappingInfo -Objekt basierend auf der Annotation in der Klasse erstellt. Anschließend wird das RequestMappingInfo -Objekt auf der Merge -Methode zurückgegeben und das Zusammenführungsobjekt schließlich zurückgegeben. Im Rückblick auf die Methode zur Detektion mit der Methode zur Methode zur GetmapingFormethod gibt es nun. Ich persönlich denke, dass dies optimiert werden kann. Bei der Beurteilung, ob die Methode überhaupt ein Handler ist, kann das erstellte RequestMappingInfo -Objekt direkt gespeichert und direkt verwendet werden, was bedeutet, dass der Prozess des Erstellens eines RequestMapingInfo -Objekts fehlt. Geben Sie dann sofort die RegisterHandlerMehTod -Methode ein, wie folgt
Protected Void RegisterHandlermethod (Objekthandler, Methode Methode, T -Mapping) {// HandleMethod HandleMethod NewHandlermethod = CreateHandlermethod (Handler, Methode); HandleMethod OldHandlermethod = HandleMethods.get (Mapping); // Überprüfen Sie, ob in der Konfiguration (OldHandlermethod! = NULL &&! OldHandlermethod.equals (newHandRermethod)) Unklarheiten vorhanden ist. OldHandlermethod.getbean () + "'Bean -Methode/n" + oldHandlermethod + "zugeordnet."); } this.Handlermethods.put (Mapping, NewHandlermethod); if (logger.issinfoenabled ()) {logger.info ("maped /" " + mapping +" /"auf" + newHandRerMethod); } // Erhalten Sie den Wert von @RequestMapping-Annotation und fügen Sie dann den Value-> RequestMappingInfo-Mapping-Datensatz zum URLMAP-Set <string> musters = getMapPingPathPattern (Mapping) hinzu; für (String -Muster: Muster) {if (! getPathMatcher (). IsSpattern (Muster)) {this.urlmap.add (Muster, Mapping); }}} Hier ist die Art von t RequestMappingInfo. Dieses Objekt ist die relevanten Informationen der Annotation der RequestMapping der Methode unter dem spezifischen Controller. Eine Annotation für Requestmapping entspricht einem RequestMapingInfo -Objekt. HandleMethod ähnelt RequestMappingInfo und ist eine Kapselung spezifischer Verarbeitungsmethoden unter Controlelr. Schauen Sie sich zunächst die erste Zeile der Methode an und erstellen Sie ein HandleMethod -Objekt basierend auf Handler und MEHTHOD. Die zweite Zeile verwendet HandleMethods -Karte, um das Handler -Methode zu erhalten, das der aktuellen Zuordnung entspricht. Stellen Sie dann fest, ob dieselbe RequestMapping -Konfiguration vorhanden ist. Die folgende Konfiguration führt dazu, dass der hier geworfene geworfen wird
Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map...
abnormal
@Controller @RequestMapPing ("/zweifigousTest") public class mehrdeutigTestController {@RequestMapping (value = "/test1") @Responbody public String test1 () {return "Methode test1"; } @RequestMapping (value = "/test1") @ResponseBody public String test2 () {return "Methode test2"; }} Überprüfen Sie, ob die RequestMapping -Konfiguration während der SpringMVC -Startphase (Initialisierung) Unklarheit ist. Dies ist eines der Dinge, die nach Unklarheiten geprüft werden müssen (ein Ort, an dem Sie nach der Laufzeit nach Mehrdeutigkeit suchen, wird später erwähnt). Nachdem bestätigt wurde, dass die Konfiguration normal ist, werden die RequestMappingInfo- und HandleMethod -Objekte zu HandleMethods (LinkedHasMap) hinzugefügt, und dann wird der annotierte Wert von RequestMapping und ReuqestMapingInfo zum URLMAP hinzugefügt.
Einfache Zusammenfassung der RegisterHandlermethod -Methode
Es gibt drei Hauptaufgaben dieser Methode
1. Überprüfen Sie, ob die RequestMapping -Annotationskonfiguration Unklarheit ist.
2. Erstellen Sie eine Karte von RequestMappingInfo zu HandleMethod. Diese Karte ist die Mitgliedsvariablen -Handler -Methoden von AbstractHandlermethodmapping. LinkedHasMap.
3. Erstellen Sie die Mitgliedsvariablen -URLMAP von AbstractHandlermethodmapping und MultivalUemap. Diese Datenstruktur kann als MAP> verstanden werden. Der String -Typ -Schlüssel speichert den Wert der RequestMapping -Annotation für die Verarbeitungsmethode. Es ist der spezifische Uri
Zuerst gibt es den folgenden Controller
@Controller @RequestMapping ("/urlmap") öffentliche Klasse URLMAPCONTROLLER {@RequestMapPing (value = "/test1", method = requestMethod.get) @Responbody public String test1 () {return "method test1"; } @RequestMapping (value = "/test1") @ResponseBody public String test2 () {return "Methode test2"; } @RequestMapping (value = "/test3") @ResponseBody public String test3 () {return "methode test3"; }} Nach Abschluss der Initialisierung ist die Struktur der URLMAP, die dem AbstractHandlermethodmapping entspricht, wie folgt
Das obige ist der Hauptprozess der SpringMVC -Initialisierung
Suchprozess
Um den Suchprozess mit einer Frage zu verstehen, sind die folgenden Controller verfügbar
@Controller @RequestMapping ("/Lookuptest") public class LookuptestController {@RequestMapping (value = "/test1", method = requestMethod.get) @ResponseBody public String test1 () {return "Methode test1"; } @RequestMapping (value = "/test1", Headers = "referer = https: //www.baidu.com") @ResponseBody public String test2 () {return "Methode test2"; } @RequestMapping (value = "/test1", params = "id = 1") @ResponseBody public String test3 () {return "methode test3"; } @RequestMapping (value = "/*") @ResponseBody public String test4 () {return "method test4"; }} Es gibt Anfragen wie folgt
Welche Methode wird diese Anfrage eingeben?
Nach Erhalt der Anfrage wird der Webcontainer (Tomcat, Jetty) zur Bearbeitung an den DispatcherServlet übergeben. Das FrameworkServlet fordert die entsprechende Anforderungsmethode auf (z. B. Anrufe doget) und dann die ProcessRequest -Methode. Geben Sie nach Eingabe der ProcessRequest -Methode nach einer Reihe von Verarbeitung die DoService -Methode in Zeile: 936 ein. Geben Sie dann die Dodispatch -Methode in Zeile856 ein. Holen Sie sich den aktuell angeforderten Prozessorhandler in Zeile: 896. Geben Sie dann die LookupHandlermethod -Methode des AbstractHandlermethodmapping ein. Der Code ist wie folgt
Protected HandleMethod LookupHandlermethod (String Lookuppath, HttpServletRequest Request) löst eine Ausnahme aus {list <Match> Matches = new ArrayList <Match> (); // DirectPathMatches basierend auf URI -Liste <T> DirectPathMatches = this.urlmap.get (Lookuppath); if (DirectPathMatches! } // Es gibt keine direkte Übereinstimmung mit RequestMappingInfo, iteriert alle RequestMappingInfo if (Matches.Empty ()) {// Keine Wahl, als alle Zuordnungen zu durchzugehen addMatchingMappings (thandlerMethods.Keyset (), übereinstimmen, Anfrage); } // das HandleMethod erhalten, das der besten Match -RequestMappingInfo entspricht (! Matches.isempty ()) {Comparator <Match> vergleicher = neuer MatchComparator (GetMappingComparator (Anfrage)); Sammelns.sort (Übereinstimmungen, Vergleicher); if (logger.istaceEnabled ()) {logger.trace ("gefunden" + minessize () + "Matching Mapping (s) für [" + Lookuppath + "]:" + Matches); } // Überprüfen Sie die Mehrdeutigkeit der Konfiguration erneut übereinstimmend BESTMATCH = MACTES.get (0); if (matches.size ()> 1) {match SecondBestMatch = Matches.get (1); if (vergleicher.comPare (BestMatch, SecondBestMatch) == 0) {Methode M1 = BestMatch.Handlermethod.getMethod (); Methode M2 = SecondBestMatch.Handlermethod.getMethod (); Neue IllegalStateException werfen ("mehrdeutige Handler -Methoden für http path '" + request.getRequesturl () + "': {" + m1 + "," + m2 + "}"); }} Handlematch (BestMatch.Mapping, Lookuppath, Anfrage); return BESTMATCH.HANDRERMETHOD; } else {return Handlenomatch (HandleMethods.Keyset (), Lookuppath, Anfrage); }} Geben Sie die LookupHandlermethod -Methode ein, wobei Lookuppath = "/Lookuptest/test1" laut Lookuppath, dh dem angeforderten URI. Suchen Sie direkt die URLMAP und erhalten Sie die RequestMappingInfo -Liste, die direkt übereinstimmt. Hier werden wir mit 3 RequestMappingInfos übereinstimmen. wie folgt
Geben Sie dann die Methode addMatchingMappings ein
private void addMatchingMappings (Sammlung <T> Zuordnungen, List <Match> Matches, httpServletRequest -Anforderung) {für (t Mapping: Mappings) {t match = getMatchingMapping (Mapping, Anfrage); if (match! }}} Die Verantwortung dieser Methode besteht darin, zu durchqueren, ob der aktuelle URI und der RequestMappingInfo in Zuordnungen übereinstimmen können, und erstellen Sie dieselbe RequestMapingInfo -Objekt. Holen Sie sich dann den HandleMethod, der dem RequestMappingInfo entspricht. Erstellen Sie dann ein Match -Objekt und fügen Sie es der Spielliste hinzu. Kehren Sie nach der Ausführung der AddMatchingMappings -Methode zu LookupHandlermethod zurück. Zu diesem Zeitpunkt haben Übereinstimmungen immer noch 3 RequestMappingInfo -Objekte, die übereinstimmen können. Der nächste Prozess besteht darin, die Liste der Matchers zu sortieren und dann das erste Element der Liste als die beste Übereinstimmung zu erhalten. Gibt den Handleermethod des Spiels zurück. Hier geben wir die Vergleichsmethode von RequestMappingInfo ein und schauen Sie sich die spezifische Sortierlogik an. Der Code ist wie folgt
public int vergleicheto (RequestMappingInfo Andere, httpServletRequest -Anforderung) {int result = musterscondition.comPareto (other.getPatternScondition (), request); if (result! = 0) {return Ergebnis; } result = paramscondition.comPareto (other.getParamscondition (), request); if (result! = 0) {return Ergebnis; } result = Headerscondition.comPareto (other.getheadersCondition (), request); if (result! = 0) {return Ergebnis; } result = ConsumerCondition.comPareto (other.getConsumescondition (), request); if (result! = 0) {return Ergebnis; } result = protousSeScondition.comPareto (other.getProDucescondition (), request); if (result! = 0) {return Ergebnis; } result = methodeScondition.comPareto (other.getMethodscondition (), request); if (result! = 0) {return Ergebnis; } result = customConditionHolder.comPareto (other.customconditionär, Anfrage); if (result! = 0) {return Ergebnis; } return 0;} Wie Sie im Code sehen können, ist die Reihenfolge der Übereinstimmungen Wert> Params> Header> Verbraucher> Erzeugung> Methoden> Benutzerdefiniert. Wenn man dies sieht, kann die vorherige Frage leicht beantwortet werden. Bei gleichem Wert können Parameter zuerst übereinstimmen. Diese Anfrage gibt also die Methode test3 () ein. Gehen Sie zurück zu LookupHandlermethod und finden Sie HandleMethod. SpringMVC überprüft hier die Mehrdeutigkeit der Konfiguration erneut. Das Prinzip des Schecks besteht hier darin, die beiden RequestMappingInfos mit dem höchsten Übereinstimmung zu vergleichen. Hier kann es Fragen geben, dass bei der Initialisierung von SpringMVC eine mehrdeutige Konfigurationsprüfung gibt. Warum wird es hier erneut überprüft? Wenn der Controller jetzt zwei Methoden gibt, kann die folgende Konfiguration durch Initialisierungsdeutigkeit überprüft werden.
@RequestMapping (value = "/test5", method = {requestMethod.get, requestMethod.post})@responseBodypublic String test5 () {return "methode test5";}@requestMapping (value = "/test5", methode = {requestMethod.get. Test6 ";} Führen Sie nun die http: // localhost: 8080/SpringMVC-Demo/Lookuptest/test5-Anforderung aus, und sie wird in die LookupHandlermethod-Methode geworfen
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/SpringMVC-Demo/LookupTest/test5' Ausnahme. Die Ausnahme wird hierher ausgelöst, da die Vergleichsmethode der RequestMethodsRequestCondition die Vergleichsmethodennummer ist. Der Code ist wie folgt
public int vergleicheto (RequestMethodsRequestCondition Andere, httpServletRequest -Anforderung) {return SonstigeWann passt Platzhalter? Wenn der RequestMappingInfo, der direkt mit dem Wert übereinstimmt, nicht über URLMAP erhalten werden kann, wird die Wildcard -Matching verwendet, um die Methode für addMatchingMappings einzugeben.
Zusammenfassen
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Referenzwert für das Studium oder die Arbeit eines jeden hat. Wenn Sie Fragen haben, können Sie eine Nachricht zur Kommunikation überlassen. Vielen Dank für Ihre Unterstützung bei Wulin.com.