0 Résumé
Cet article explique brièvement le lien de mappage de processeur de SpringMVC à partir du niveau du code source, c'est-à-dire le processus détaillé de recherche du contrôleur
1 processus de demande SpringMVC
Le contrôleur recherche les étapes 1 à 2 correspondant à l'image ci-dessus
SpringMVC Tableau de débit d'opération détaillée
2 processus d'initialisation de SpringMVC
2.1 Comprenez d'abord deux catégories
1.Requestmappinginfo
Annotation de la demande de demande d'encapsulation
Contient des informations pertinentes sur les en-têtes de demande HTTP
Une instance correspond à une annotation de la mise en évidence
2.Handlemmethod
Méthode de traitement des demandes de contrôleur encapsulant
Comprend l'objet bean sur lequel appartient la méthode, l'objet de la méthode correspondant à la méthode, les paramètres de la méthode, etc.
Requestmappinghandlermapping Relations de succession
Pendant l'initialisation de Springmvc
Exécutez d'abord le postpropertieset de requestmappinghandlermapping
Entrez ensuite dans l'abstracthandlermethodmapping
Cette méthode entrera dans les lèvres de cette classe
Responsable de la numérisation des haricots à partir d'ApplicationContext, puis de la recherche et de l'enregistrement des méthodes de processeur à partir de beans
// scanne des beans dans l'applicationContext, détecter et enregistrer les méthodes du gestionnaire. getApplicationContext (). getBeAnNamesForty (object.class)); // Transférer le tableau de nom de haricot pour (String Beanname: BeanNames) {// IsHandler jugera si la définition du bean contient une annotation du contrôleur ou une annotation de mise en évidence en fonction du bean. If (isHandler (getApplicationContext (). GetType (beanname))) {DeteteCthandLerMethods (beanname); }} handlerMethodsinitialized (GethandlerMethods ());} Requestmappinghandlermapping # ishandler
La méthode ci-dessus consiste à déterminer si la définition actuelle de bean contient une annotation du contrôleur ou une annotation de la carte de demande
Si seulement la mise en œuvre de la demande prend effet? Non!
Parce que dans ce cas, la classe ne sera pas enregistrée en tant que haricot à ressort lors de l'initialisation du ressort, et la classe ne sera pas traversée lors de la traversée des noms de haricots, il est donc acceptable de remplacer le contrôleur par compoent ici, mais cela ne se fait pas en général
Après avoir confirmé que le haricot est un gestionnaire, la méthode de gestionnaire spécifique sera trouvée à partir du haricot (c'est-à-dire la méthode de traitement de la demande définie dans la classe de contrôleur). Le code de recherche est le suivant
/ ** * Recherchez des méthodes de gestionnaire dans un gestionnaire * @param Handler Le nom de bean d'un gestionnaire ou une instance de gestionnaire * / Protected void DeteteCthandLerMethods (Final Object Handler) {// Obtenez l'objet de classe de la chaîne de bean Contrôleur actuelle <?> HandlerType = (Handler instanceof String)? getApplicationContext (). GetType ((String) Handler): handler.getClass (); // Évitez les appels répétés pour getMappingFormethod pour reconstruire la carte de demande de mise en instance finale <méthode, t> mappings = new identityhashmap <méthode, t> (); // Comme ci-dessus, c'est aussi l'objet de classe de la classe finale du manteau de contrôleur <?> UserType = classutils.getUserclass (handlerType); // Obtenez toutes les méthodes de gestionnaire du bean actuel // Définissez s'il a des demandes de demande en fonction de la méthode // s'il y en a, créez un jeu d'instructions de demande de requête (usertype, new MethodFilter () {@Override public boolean mathes (méthode) {t mapping = getMapproformy null) {mappings.put (méthode, mappage); // Voyagez et enregistrez toute la méthode du gestionnaire du bean actuel pour (méthode Méthode: méthodes) {// Registre de la méthode du gestionnaire et entrez la méthode suivante RegisterHandleMethod (gestionnaire, méthode, mappings.get (méthode)); } Il y a deux endroits dans le code ci-dessus qui appelle GetMappingFormethod
Créer une mise en place de demande en utilisant la méthode et le niveau de type annotation de demande de demande
@Override Protected requestmappingInfo getMappingFormETHod (méthode Method, class <?> HandlerType) {requestmappingInfo info = null; // Obtenez la méthode @RequestMapping de requestmapping methodannotation = annotationutils.findannotation (méthode, requestmapping.class); if (methodannotation! = null) {requestCondition <?> MethodCondition = getCustomThodCondition (méthode); info = CreateRequestMappingInfo (méthodannotation, méthodeCondition); // obtient l'annotation @requatestmapping du bean à laquelle la méthode appartient à la mise en œuvre de demande de type type de type = annotationutils.findannotation (handlertype, requestmapping.class); if (typeAnNotation! = null) {requestCondition <?> TypeCondition = getCustomTyPecondition (handlerType); // fusionner deux @RequestMapping Annotations info = CreateRequestMappingInfo (typeanNotation, TypeCondition) .combine (info); }} retour des informations; } Le but de cette méthode est de créer un objet requestmappingInfo basé sur la méthode du gestionnaire. Tout d'abord, déterminez si le MeHTOD contient l'annotation de demande de demande. Dans l'affirmative, créez un objet requestmappingInfo directement en fonction du contenu de l'annotation. Après la création, déterminez si le haricot auquel la méthode actuelle contient également l'annotation de la mise en évidence. Si cette annotation est incluse, un objet requestmappingInfo sera créé en fonction de l'annotation sur la classe. Ensuite, l'objet requestmappingInfo sur la méthode de fusion est renvoyé et l'objet fusionné est finalement renvoyé. Maintenant, en regardant en arrière la méthode DetetecthandlerMethods, il y a deux appels à la méthode GetMappingFormethod. Je pense personnellement que cela peut être optimisé. Lorsque vous jugez si la méthode est un gestionnaire en premier lieu, l'objet CreatedMappingInfo peut être enregistré et utilisé directement plus tard, ce qui signifie que le processus de création d'un objet de demande de gisement enInfo est manquant. Entrez ensuite immédiatement la méthode RegisterHandlermehtod, comme suit
Protected void RegisterHandlerMethod (Handler d'objet, méthode de la méthode, mappage t) {// créer handlerMethod handlerMethod newhandlerMethod = CreateHandlerMethod (gestionnaire, méthode); HandlerMethod oldHandlerMethod = handlerMethods.get (mappage); // Vérifiez s'il y a une ambiguïté dans la configuration if (oldHandlerMethod! = Null &&! OldhandlerMethod.equals (newhandlerMethod)) {lancez new illégalstateException ("Mappage ambigu trouvé. OldHandlerMethod.getBean () + "'' Méthode de bean / n" + oldHandlerMethod + "Mapted."); } this.handlerMethods.put (mappage, newhandlerMethod); if (logger.isinfoenabled ()) {logger.info ("mappé /" "+ mapping +" / "sur" + newhandlerMethod); } // Obtenez la valeur de l'annotation @RequestMapping, puis ajoutez l'enregistrement de mappage de valeur-> requestmappingInfo à l'URLMap set <string> motifs = getMappingPathPattern (mapping); for (String motif: motifs) {if (! getPathMatcher (). Ispattern (modèle)) {this.urlmap.add (modèle, mappage); }}} Ici, le type de T est demandemappinginfo. Cet objet est les informations pertinentes de l'annotation de la mise en évidence de la méthode sous le contrôleur spécifique encapsulé. Une annotation de la mise en évidence correspond à un objet requestmappingInfo. HandlerMethod est similaire à requiermappinginfo et est une encapsulation de méthodes de traitement spécifiques sous ControlELR. Regardez d'abord la première ligne de la méthode et créez un objet HandlerMethod basé sur Handler et Mehthod. La deuxième ligne utilise la carte HandLerMethods pour obtenir le handlermethod correspondant au mappage actuel. Déterminez ensuite s'il existe la même configuration de carter de demande. La configuration suivante provoquera le lancement ici
Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map...
anormal
@ Contrôleur @ requestmapping ("/ ambiguousTest") classe publique AmbiguLSTestController {@RequestMapping (value = "/ test1") @ResponseBody public String Test1 () {return "Method Test1"; } @RequestMapping (value = "/ test1") @ResponseBody public String test2 () {return "Method Test2"; }} Vérifiez si la configuration de la carte de demande est une ambiguïté pendant la phase de démarrage (initialisation) de SpringMVC, qui est l'une des choses pour vérifier l'ambiguïté (un endroit pour vérifier l'ambiguïté au moment de l'exécution sera mentionné plus tard). Ensuite, après avoir confirmé que la configuration est normale, les objets de requête-appuyant surInfo et HandlerMethod seront ajoutés à HandlerMethods (LinkedHashMap), puis la valeur annotée de la demande de demande et les objets REUQESTMAPPINGInfo seront ajoutés à l'URLMAP.
Résumé simple de la méthode RegisterHandlerMethod
Il y a trois principales responsabilités de cette méthode
1. Vérifiez si la configuration d'annotation de la mise en évidence est une ambiguïté.
2. Construisez une carte de requestmappinginfo à HandlerMethod. Cette carte est la variable membre des handlerméthodes de l'abstracthandlermethodmapping. LinkedHashmap.
3. Construisez l'URLMAP variable membre de l'abstracthandlerthodmapping et du multivalemap. Cette structure de données peut être comprise comme MAP>. La touche de type de chaîne stocke la valeur de l'annotation de la mise en évidence sur la méthode de traitement. C'est l'uri spécifique
Il y a d'abord le contrôleur suivant
@ Contrôleur @ requestmapping ("/ urlmap") classe publique URLMAPController {@RequestMapping (value = "/ test1", méthode = requestMethod.get) @ResponseBody public String test1 () {return "Method test1"; } @RequestMapping (value = "/ test1") @ResponseBody public String test2 () {return "Method Test2"; } @RequestMapping (value = "/ test3") @ResponseBody public String test3 () {return "Method Test3"; }} Une fois l'initialisation terminée, la structure de l'URLMAP correspondant à l'abstracthandlerthodmapping est la suivante
Ce qui précède est le processus principal de l'initialisation de SpringMVC
Processus de recherche
Afin de comprendre le processus de recherche, avec une question, les contrôleurs suivants sont disponibles
@ Contrôleur @ requestmapping ("/ lookuptest") classe publique LookupTestController {@RequestMapping (value = "/ test1", méthode = requestMethod.get) @ResponseBody public String test1 () {return "Method test1"; } @RequestMapping (value = "/ test1", en-tête = "référer = https: //www.baidu.com") @ResponseBody public String test2 () {return "Method Test2"; } @RequestMapping (value = "/ test1", params = "id = 1") @ResponseBody public String test3 () {return "Method Test3"; } @RequestMapping (value = "/ *") @ResponseBody public String test4 () {return "Method Test4"; }} Il y a des demandes comme suit
Quelle méthode cette demande entrera-t-elle?
Après avoir reçu la demande, le conteneur Web (Tomcat, Jetty) est remis au Dispatcherservlet pour le traitement. Le frameworkservlet appelle la méthode de demande correspondante (par exemple: obtenir des appels doget), puis appelle la méthode ProcessRequest. Après être entré dans la méthode ProcessRequest, après une série de traitement, entrez la méthode Doservice en ligne: 936. Entrez ensuite la méthode Dodispatch en ligne856. Obtenez le gestionnaire de processeur actuellement demandé en ligne: 896. Entrez ensuite la méthode LookupHandlerMethod of AbstracthandLerMethodmapping. Le code est le suivant
HandLerMethod Protected LookupHandlerMethod (String lookuppath, httpServLetRequest) lance l'exception {list <match> matches = new ArrayList <Cath> (); // obtient directementPathmatches basé sur la liste URI <T> DirectPathMatches = this.urlmap.get (lookuppath); if (DirectPathMatches! = null) {addMatchingMappings (directspathmatches, matchs, demande); } // Il n'y a pas de correspondance de correspondance directe, itère via tous les demandes demappingInfo if (matches.isempty ()) {// pas le choix que de passer par tous les mappings addMatchingMappings (this.handlerMods.KeySet (), correspond, demande); } // obtient le handlerMethod correspondant à la meilleure correspondance de jeu de correspondance enInfo if (! Matches.iSempty ()) {Comparator <Cath> Comparator = new MatchComparator (getMappingComparator (request)); Collection.Sort (matchs, comparateur); if (logger.istraceenabled ()) {logger.trace ("Found" + Matches.Size () + "MACHAPPAGE (s) de correspondance pour [" + lookuppath + "]:" + correspond); } // Vérifiez à nouveau l'ambiguïté de la configuration correspond à BestMatch = Matches.get (0); if (Matches.size ()> 1) {Match SecondBestMatch = Matches.get (1); if (comparateur.compare (bestmatch, secondBestMatch) == 0) {méthode m1 = bestmatch.handlerMethod.getMethod (); Méthode m2 = secondBestMatch.HandlerMethod.getMethod (); Jetez un nouveau IllégalStateException ("Méthodes de gestionnaire ambigu mappées pour Http Path '" + request.getRequestUrl () + "': {" + m1 + "," + m2 + "}"); }} handlematch (bestmatch.mapping, lookuppath, demande); return bestmatch.handlerMethod; } else {return handLenomatch (handlerMethods.KeySet (), lookuppath, request); }} Entrez la méthode LookupHandlerMethod, où lookuppath = "/ lookuptest / test1", selon Lookuppath, c'est-à-dire l'uri demandé. Trouvez directement l'URLMAP et obtenez la liste RequestMappingInfo qui correspond directement. Ici, nous correspondrons à 3 demandes de jeu de demandes. comme suit
Entrez ensuite la méthode AddMatchingMappings
private void addMatchingMappings (collection <T> mappings, list <match> correspond, httpservletRequest request) {for (mapping: mappings) {t match = getmatchingmapping (mapping, request); if (match! = null) {matches.add (new Match (match, handlerMethods.get (mapping))); }}} La responsabilité de cette méthode est de parcourir si l'URI demandé actuel et la mise en scène de demande dans les mappages peuvent correspondre et, dans l'affirmative, créent le même objet de demande de jeu de requête. Ensuite, obtenez le HandlerMethod correspondant à requestmappingInfo. Créez ensuite un objet Match et ajoutez-le à la liste des correspondances. Après avoir exécuté la méthode AddMatchingMappings, revenez à LookupHandlerMethod. À l'heure actuelle, les matchs ont encore 3 objets de requête enInfo qui peuvent correspondre. Le processus suivant consiste à trier la liste des matchs, puis à obtenir le premier élément de la liste comme la meilleure correspondance. Renvoie le HandlerMethod du match. Ici, nous entrons dans la méthode compareto de requiermappinginfo et jetons un coup d'œil à la logique de tri spécifique. Le code est le suivant
public int compareto (requestmappingInfo Autre, httpservletRequest request) {int result = patternScondition.Compareto (autre.getPatternScondition (), request); if (result! = 0) {return result; } result = paramscondition.compareto (autre.getParamScondition (), demande); if (result! = 0) {return result; } result = headerscondition.compareto (autre.GetHedersCondition (), demande); if (result! = 0) {return result; } result = consommationCondition.compareto (autre.getConsumeScondition (), demande); if (result! = 0) {return result; } result = produceScondition .......pampionto (autre.getProduceCondition (), demande); if (result! = 0) {return result; } result = méthodeScondition.Careto (autre.GetMethodScondition (), demande); if (result! = 0) {return result; } Result = CustomConditionholder. .Pareto (autre.CustomConditionholder, demande); if (result! = 0) {return result; } retourne 0;} Comme vous pouvez le voir dans le code, l'ordre des correspondances est la valeur> Params> En-têtes> Consume> Production> Méthodes> Custom. Voyant cela, la question précédente peut être facilement répondue. Dans le cas de la même valeur, les paramètres peuvent correspondre en premier. De sorte que cette demande entrera la méthode Test3 (). Retournez à la recherche de lookLerMethod et trouvez HandlerMethod. SpringMVC vérifiera à nouveau l'ambiguïté de la configuration ici. Le principe du chèque ici est de comparer les deux demandes de mise en œuvre enInfos avec le diplôme de correspondance le plus élevé. Il peut y avoir des questions ici que lors de l'initialisation de SpringMVC, il y a une vérification de configuration ambiguë, pourquoi est-elle à nouveau vérifiée ici? S'il y a maintenant deux méthodes dans le contrôleur, la configuration suivante peut être vérifiée par l'ambiguïté d'initialisation.
@RequestMapping (value = "/ test5", méthode = {requestMethod.get, requestMethod.post}) @ réponse () String Test5 () {return "méthode test5";} @ requestmapping (value = "/ test5", méthode = {requestMethod.get, requestMethod.delete}) @ réponse. Maintenant, exécutez le http: // localhost: 8080 / springmvc-demo / lookuptest / test5, et il sera jeté dans la méthode de recherche
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/SpringMVC-Demo/LookupTest/test5' exception. L'exception est lancée ici parce que la méthode compareto de requestMethodSrequestCondition est le numéro de méthode de comparaison. Le code est le suivant
public int compareto (requestMethodsRequestCondition autre, httpServLetRequest request) {return autre.methods.size () - this.methods.size ();}Quand le joker correspond-il? Lorsque la mise en place de demande qui correspond directement à la valeur ne peut pas être obtenue via URLMAP, la correspondance de la jogne sera utilisée pour entrer la méthode AddMatchingMappings.
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.