0 ملخص
تشرح هذه المقالة بإيجاز رابط تعيين المعالج لـ springMVC من مستوى الكود المصدر ، أي العملية التفصيلية للعثور على وحدة التحكم
1 عملية طلب springmvc
يبحث وحدة التحكم عن الخطوات من 1 إلى 2 المقابلة للصورة أعلاه
SpringMVC مخطط تدفق العمليات التفصيلية
2 عملية تهيئة SpringMVC
2.1 أولاً فهم فئتين
1.RequestMappingInfo
التغليف طلب التعليق التوضيحي
يحتوي على معلومات ذات صلة حول رؤوس طلب HTTP
مثيل يتوافق مع شرح التوضيح
2.handlermethod
طريقة التعامل مع طلبات وحدة التحكم
يتضمن كائن الفول الذي تنتمي إليه الطريقة ، كائن الطريقة المقابل للطريقة ، ومعلمات الطريقة ، إلخ.
requestMappingHandLermapping علاقة الميراث
خلال تهيئة SpringMVC
قم أولاً بتنفيذ ما بعد requestMappingHandLermapping
ثم أدخل Artracthandlermethodmapping بعد propertiesset
ستدخل هذه الطريقة في inithandlermethods في هذه الفئة
مسؤول عن مسح الفاصوليا من ApplicationContext ، ثم العثور على أساليب المعالج وتسجيله من الفول
// مسح الفاصوليا في ApplicationContext ، اكتشاف وتسجيل طريقة المعالج. getApplicationContext (). getBeanNamesfortype (object.class)) ؛ // نقل صفيف Beanname لـ (String Beanname: Beannames) {// Ishandler سيحكم على ما إذا كان تعريف الفاصوليا يحتوي على تعليق توضيحي للوحدة أو طلب التعليقات التوضيحية بناءً على الفول. if (isHandler (getApplicationContext (). }} معالجتها (gethandlermethods ()) ؛ requestMappingHandLermapping#Ishandler
الطريقة المذكورة أعلاه هي تحديد ما إذا كان تعريف الفول الحالي يحتوي على تعليق توضيحي أو شرح توضيح للطلب
إذا كان الطلب فقط يسري سريان؟ لا!
لأنه في هذه الحالة ، لن يتم تسجيل الفصل كحبة زنبركية عند تهيئة الربيع ، ولن يتم اجتياز الفصل عند اجتياز أسماء الأقرب
بعد التأكيد على أن الفول هو معالج ، سيتم العثور على طريقة المعالج المحددة من الفول (أي ، طريقة معالجة الطلب المحددة في فئة وحدة التحكم). رمز البحث كما يلي
/** * ابحث عن أساليب المعالج في معالج * param معالج الفاصوليا للمعالج أو مثيل معالج */void detecthandlermethods (معالج الكائن النهائي) {// احصل على كائن الفئة من وحدة التحكم الحالية beanclass <؟ getApplicationContext (). gettype ((سلسلة) معالج): handler.getClass () ؛ // تجنب المكالمات المتكررة إلى getMappingFormethod لإعادة بناء mustermappinginfo الخريطة النهائية <method ، t> mappings = new IdentityHashMap <method ، t> () ؛ // كما هو مذكور أعلاه ، فهو أيضًا كائن فئة من فئة وحدة التحكم في الفاصوليا <؟> userType = classUtils.getuserClass (HandlerType) ؛ // احصل على جميع أساليب المعالج للفول الحالي // تحديد ما إذا كان لديه طلب وفقًا للطريقة // إذا كان هناك ، قم بإنشاء مجموعة مثيل requestMappingInfo <tream> methods = handlermethodselector.selectmethods (usertype ، methingfilter () {override public match (mapping) NULL) // السفر وتسجيل جميع طريقة معالج الحبة الحالية لـ (طريقة الطريقة: الأساليب) {// تسجيل طريقة المعالج وأدخل الطريقة التالية registerlermethod (معالج ، طريقة ، mapting.get (الطريقة)) ؛ } يوجد مكانان في الرمز أعلاه يدعو getMappingFormeThod
إنشاء requestMappingInfo باستخدام التعليق التوضيحي للطلب
OverRide محمي requestMappingInfo getMappingFormethod (طريقة الطريقة ، الفئة <؟> HandlerType) {requestMappingInfo info = null ؛ // احصل على طريقة requestmapping method requestMapping MethodAntAnotation = enrotationUtils.FindAnnotation (الطريقة ، requestMapping.class) ؛ if (methodAnnotation! = null) {requestCondition <؟> methodCondition = getCustomMethodCondition (method) ؛ info = createrequestmappingInfo (methodannotation ، methodCondition) ؛ // احصل على شرح @requTestMapping للفاصوليا التي تنتمي إليها الطريقة التي تطلبها typeannotation = annotationUtils.findannotation (HandlerType ، requestMapping.class) ؛ if (typeannotation! = null) {requestCondition <؟> typecondition = getCustomTyPecondition (HandlerType) ؛ // دمج اثنين @requestmapping info = createrequestMappingInfo (typeannotation ، typecondition) .combine (info) ؛ }} معلومات الإرجاع ؛ } الغرض من هذه الطريقة هو إنشاء كائن requestMappingInfo استنادًا إلى طريقة طريقة المعالج. أولاً ، حدد ما إذا كان Mehtod يحتوي على شرح requestMpping. إذا كان الأمر كذلك ، قم بإنشاء كائن requestMappingInfo بناءً على محتوى التعليق التوضيحي. بعد الإنشاء ، حدد ما إذا كانت الطريقة التي تحتوي عليها الطريقة الحالية أيضًا على شرح طلب الطلب. إذا تم تضمين هذا التعليق ، فسيتم إنشاء كائن requestMappingInfo بناءً على التعليق التوضيحي على الفصل. بعد ذلك ، يتم إرجاع كائن requestMappingInfo على طريقة الدمج ، ويتم إرجاع الكائن المدمج أخيرًا. الآن ، إذا نظرنا إلى الوراء في طريقة DetectHandlerMethods ، هناك مكالمتان لصالح طريقة GetMappingFormethod. أنا شخصياً أعتقد أن هذا يمكن تحسينه. عند الحكم على ما إذا كانت الطريقة هي معالج في المقام الأول ، يمكن حفظ كائن requestMappingInfo الذي تم إنشاؤه واستخدامه مباشرة لاحقًا ، مما يعني أن عملية إنشاء كائن requestMappingInfo مفقود. ثم أدخل فورًا طريقة registerLermeHtoD ، على النحو التالي
Void void registerlermethod (معالج الكائن ، طريقة الطريقة ، رسم الخرائط) {// إنشاء Handlermethod Handlermethod NewHandlerMethod = createHandlermethod (معالج ، الطريقة) ؛ HandlerMethod oldhandlermethod = handlermethods.get (رسم الخرائط) ؛ // تحقق مما إذا كان هناك غموض في التكوين إذا (oldhandlermethod! = null &&! oldhandlermethod.equals (newHandlermethod)) {رمي جديد غير alficalstateException ("تم العثور على خرائط غامضة. oldhandlermethod.getBean () + "'' method/n" + oldhandlermethod + "medped.") ؛ } this.handlermethods.put (Mapping ، NewHandlermethod) ؛ if (logger.isinfoEnabled ()) {logger.info ("medped /" " + mapping +" /"on" + newHandlerMethod) ؛ } // احصل على قيمة التعليق التوضيحي @requestmapping ، ثم أضف سجل تعيين requestMappingInfo إلى مجموعة urlmap <string> أنماط = getMappathpattern (تعيين) ؛ لـ (نمط السلسلة: الأنماط) {if (! getPathMatcher (). isPattern (pattern)) {this.urlmap.add (نمط ، رسم الخرائط) ؛ }}} هنا نوع t هو requestMappingInfo. هذا الكائن هو المعلومات ذات الصلة بتعليقات طلب الطلب للطريقة تحت وحدة التحكم المحددة المغطاة. يتوافق شرح requestmapping مع كائن requestMappingInfo. يشبه HandlerMethod requestMappingInfo ، وهو عبارة عن تغليف لطرق المعالجة المحددة تحت ControlLr. انظر أولاً إلى السطر الأول من الطريقة وإنشاء كائن HandlerMethod يعتمد على المعالج و Mehthod. يستخدم السطر الثاني خريطة HandlerMethods للحصول على معالجة المعهد المقابلة للرسم التعريفي الحالي. ثم حدد ما إذا كان تكوين الطلب نفسه موجود. سوف يتسبب التكوين التالي في الإلقاء هنا
Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map...
غير طبيعي
@controller @requestMapping ("/vibigoustest") الفئة العامة الغامضة stestController {REquestMapping (value = "/test1") @Responsebody public test1 () {return "method test1" ؛ } @requestmapping (value = "/test1") responsebody public string test2 () {return "method test2" ؛ }} تحقق مما إذا كان تكوين الطلب هو الغموض خلال مرحلة بدء التشغيل (التهيئة) SPRINGMVC ، والتي تعد واحدة من الأشياء التي يجب التحقق من الغموض (سيتم ذكر مكان للتحقق من الغموض في وقت التشغيل لاحقًا). بعد ذلك ، بعد التأكيد على أن التكوين طبيعي ، ستتم إضافة كائنات requestMappingInfo و HandlerMethod إلى معدات المعالجة (LinkedHashMap) ، ثم تتم إضافة قيمة requestmapping request و reuqestmappinginfo إلى urlmap.
ملخص بسيط لطريقة registerLermethod
هناك ثلاث مسؤوليات رئيسية لهذه الطريقة
1. تحقق مما إذا كان تكوين التعليق التوضيحي للطلب هو الغموض.
2. بناء خريطة من requestMappingInfo إلى معالجة المعالجة. هذه الخريطة هي عهد متغير الأعضاء من AbstracthandlermethodMapping. LinkedHashMap.
3. بناء urlmap المتغير العضو من Artracthandlermethodmapping و multivaluemap. يمكن فهم بنية البيانات هذه على أنها خريطة>. يقوم مفتاح نوع السلسلة بتخزين قيمة شرح الطلب على طريقة المعالجة. إنه URI المحدد
أولاً هناك وحدة التحكم التالية
@controller @requestMapping ("/urlmap") الفئة العامة urlMapController {REquestMapping (value = "/test1" ، method = requestMethod.get) responseBond public test1 () {return "test1" ؛ } @requestmapping (value = "/test1") responsebody public string test2 () {return "method test2" ؛ } @requestmapping (value = "/test3") responsebody public string test3 () {return "method test3" ؛ }} بعد الانتهاء من التهيئة ، يكون بنية urlmap المقابلة لـ Argtracthandlermethodmapping كما يلي
ما سبق هو العملية الرئيسية لتهيئة springMVC
عملية البحث
من أجل فهم عملية البحث ، مع سؤال ، تتوفر وحدات التحكم التالية
@controller @requestMapping ("/lookuptest") الفئة العامة lookuptestController {REquestMapping (value = "/test1" ، method = requestMethod.get) responsebody public test1 () {return "test1" ؛ } @requestmapping (value = "/test1" ، headers = "enderer = https: //www.baidu.com") responsebody public test2 () {return "method test2" ؛ } requestMapping (value = "/test1" ، params = "id = 1") responseBond public test3 () {return "method test3" ؛ } @requestmapping (value = "/*") Responsebody public string test4 () {return "method test4" ؛ }} هناك طلبات على النحو التالي
ما هي الطريقة التي سيؤدي بها هذا الطلب إلى إدخال؟
بعد استلام الطلب ، يتم تسليم حاوية الويب (Tomcat ، Jetty) إلى مرسل Servatcherservlet للمعالجة. يستدعي FramoWorkServlet طريقة الطلب المقابل (على سبيل المثال: الحصول على المكالمات Doge) ، ثم يستدعي طريقة ProcessRequest. بعد إدخال طريقة ProcessRequest ، بعد سلسلة من المعالجة ، أدخل طريقة Doservice في السطر: 936. ثم أدخل طريقة doDispatch في السطر 856. احصل على معالج المعالج المطلوب حاليًا في السطر: 896. ثم أدخل طريقة lookuphandlermethod من ArtracthandlermethodMapping. الرمز كما يلي
محمية HandlerMethod LookupHandlerMethod (سلسلة lookuppath ، httpservletrequest طلب) يلقي الاستثناء {list <match> matches = new ArrayList <Stince> () ؛ // get directPathMatches بناءً على قائمة URI <T> directPathMatches = this.urlmap.get (lookuppath) ؛ if (directPathMatches! = null) {addMatchingMappings (directPathMatches ، Matches ، request) ؛ } // لا يوجد طلب مطابقة مباشرة ، يتكرر من خلال جميع requestMappingInfo if (matches.isempty ()) {// لا خيار سوى الذهاب من خلال جميع mappings addMatchingMappings (this.handlermethods.keyset () ، تطابق ، طلب) ؛ } // احصل على HandlerMethod المقابلة لأفضل طلب مطابقة If (! matches.isempty ()) {Comparator <STANT> comparator = new MatchComparator (getMappingComparator (request)) ؛ collections.sort (المباريات ، المقارنة) ؛ if (logger.istraceenabled ()) {logger.trace ("found" + matches.size () + "Mapping (s) mapping for [" + lookuppath + "]:" + matches) ؛ } // تحقق من غموض التكوين مرة أخرى تطابق BestMatch = matches.get (0) ؛ if (matches.size ()> 1) {matchbestMatch = matches.get (1) ؛ if (comparator.compare (BestMatch ، SecondBestMatch) == 0) {method m1 = bestmatch.handlermethod.getMethod () ؛ الطريقة M2 = SecondBestMatch.handlermethod.getMethod () ؛ قم بإلقاء NEWALLSTATEEXCESTE ("طرق معالج غامضة تم تعيينها لمسار http" + request.getRequesturl () + "': {" + m1 + "،" + m2 + "}") ؛ }} HandleMatch (bestmatch.mapping ، lookuppath ، request) ؛ إرجاع bestmatch.handlermethod ؛ } آخر {return handlenomatch (HandlerMethods.KeySet () ، lookuppath ، request) ؛ }} أدخل طريقة lookuphandlermethod ، حيث lookuppath = "/lookuptest/test1" ، وفقًا لـ lookuppath ، أي URI المطلوبة. ابحث مباشرة عن urlmap واحصل على قائمة requestMappingInfo التي تتطابق مباشرة. هنا سوف نطابق 3 requestMappingInfos. على النحو التالي
ثم أدخل طريقة AddMatchingMappings
private void addMatchingMappings (مجموعة <T> Mappings ، قائمة <Stain> Matches ، httpservletrequest request) {for (t mapping: mappings) {t match = getMatchingMapping (Mapping ، request) ؛ if (match! = null) {matches.add (تطابق جديد (المباراة ، handlermethods.get (رسم الخرائط))) ؛ }}} تتمثل مسؤولية هذه الطريقة في اجتياز ما إذا كان بإمكان URI الحالي المطلوب و requestMappingInfo مطابقة ، وإذا كان الأمر كذلك ، قم بإنشاء نفس كائن requestMappingInfo. ثم احصل على معلية معالجة المقابلة لطلب MappingInfo. ثم قم بإنشاء كائن مطابقة وأضفه إلى قائمة المباريات. بعد تنفيذ طريقة AddMatchingMappings ، ارجع إلى LookupHandlerMethod. في هذا الوقت ، لا يزال لدى المباريات 3 كائنات requestMappingInfo التي يمكن أن تتطابق. تتمثل العملية التالية في فرز قائمة المطاعم ثم الحصول على العنصر الأول من القائمة كأفضل تطابق. يعود معلية المباراة. ندخل هنا طريقة المقارنة لـ requestMappingInfo ونلقي نظرة على منطق الفرز المحدد. الرمز كما يلي
public int compareto (requestMappingInfo Other ، httpservletrequest request) {int result = patternscondition.compareto (other.getPatterNscondition () ، request) ؛ if (النتيجة! = 0) {return return ؛ } النتيجة = paramscondition.compareto (other.getparamscondition () ، طلب) ؛ if (النتيجة! = 0) {return return ؛ } النتيجة = HeaderSconDition.compareto (other.getheaderscondition () ، طلب) ؛ if (النتيجة! = 0) {return return ؛ } النتيجة = الاستهلاك extreencondition.compareto (other.getConsumSconDition () ، request) ؛ if (النتيجة! = 0) {return return ؛ } النتيجة = producesCondition.compareto (other.getProducesCondition () ، طلب) ؛ if (النتيجة! = 0) {return return ؛ } النتيجة = methodscondition.compareto (other.getMethodSconDition () ، request) ؛ if (النتيجة! = 0) {return return ؛ } النتيجة = customConditionHolder.compareto (other.customConditionHolder ، request) ؛ if (النتيجة! = 0) {return return ؛ } العودة 0 ؛} كما ترون في الكود ، فإن ترتيب المطابقات هو القيمة> params> رؤوس> استهلاك> إنتاج> طرق> مخصص. رؤية هذا ، يمكن الإجابة على السؤال السابق بسهولة. في حالة نفس القيمة ، يمكن أن تتطابق المعلمة أولاً. بحيث سيؤدي هذا الطلب إلى إدخال طريقة Test3 (). العودة إلى LookupHandlerMethod وابحث عن معهد. سوف SPRINGMVC التحقق من غموض التكوين مرة أخرى هنا. مبدأ الشيك هنا هو مقارنة اثنين من requestMappingInfos مع أعلى درجة مطابقة. قد تكون هناك أسئلة هنا عند تهيئة SpringMVC ، هناك فحص غامض للتكوين ، لماذا يتم فحصه مرة أخرى هنا؟ إذا كانت هناك طريقتان في وحدة التحكم الآن ، فيمكن فحص التكوين التالي من خلال غموض التهيئة.
requestmapping (value = "/test5" ، method = {requestMethod.get ، requestMethod.post})@reponseBodyPublic String Test5 () {return "method test5" ؛ قم الآن بتنفيذ http: // localhost: 8080/springmvc-demo/lookuptest/test5 طلب ، وسيتم إلقاؤه في طريقة lookuphandlermethod
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/SpringMVC-Demo/LookupTest/test5' . يتم طرح الاستثناء هنا لأن طريقة المقارنة لـ requestMethodSreQuestCondition هي رقم طريقة المقارنة. الرمز كما يلي
Public Int Compareto (requestmethodsRequestCondition أخرى ، طلب httpservletrequest) {return other.methods.size () - this.methods.size () ؛}متى يتطابق Wildcard؟ عندما لا يمكن الحصول على القيمة التي تتطابق مباشرة مع القيمة من خلال urlmap ، سيتم استخدام مطابقة WildCard للدخول إلى طريقة AddMatchingMappings.
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.