وحدة التحكم في الواجهة الأمامية هي الجزء الأكثر جوهريًا في إطار عمل MVC بأكمله. يتم استخدامه بشكل أساسي لاعتراض الطلبات الخارجية التي تلبي المتطلبات وتوزيع الطلبات على وحدات تحكم مختلفة للمعالجة. وفقًا لنتائج معالجة وحدة التحكم ، فإنه يولد الاستجابات المقابلة ويرسلها إلى العميل. يمكن تنفيذ وحدة التحكم في الواجهة الأمامية باستخدام Filter (يستخدم Struts2 هذه الطريقة) أو servlet (SPRING MVC Framework).
بصفتها مراقبة مسبقة ، فإن Sipatcherservlet هو مدخل خادم الويب وهو فئة MVC Spring الأكثر أهمية. خلال دورة حياتها ، يمكن تعميق فهم خادم الويب.
دورة حياة servlet
أولاً ، دعنا نتذكر دورة حياة Servlet:
تنقسم دورة حياة Servlet إلى ثلاث مراحل: [شرح مفصل لدورة حياة Servlet ومبدأ العمل]
1. طريقة init () تسمى init () في مرحلة التهيئة. بعد تحميل Servlet ، تقوم حاوية Servlet بإنشاء مثيل Servlet ويدعو طريقة Servlet's INIT () للتهيئة. تسمى طريقة init () مرة واحدة فقط خلال حياة servlet بأكملها.
2. اتصل بالطريقة Service () استجابة لمرحلة طلب العميل
3. استدعاء تدمير () طريقة في مرحلة الإنهاء
مرحلة تهيئة servlet
في اللحظات التالية ، تقوم حاوية Servlet بتحميل Servlet:
1. عندما تبدأ حاوية servlet ، يتم تحميل بعض servlets تلقائيًا. لتنفيذها ، تحتاج فقط إلى إضافة الرمز التالي بين <Servlet> </servlet> في ملف web.xml:
<loadon-startup> 1 </loadon-startup>
2. بعد بدء حاوية Servlet ، يرسل العميل طلبًا إلى Servlet لأول مرة
3. بعد تحديث ملف فئة Servlet ، إعادة تحميل servlet
هيكل المرسل
بعد مراجعة المعرفة المذكورة أعلاه ، دعونا نلقي نظرة على بنية Sipatcherservlet:
يرث Dispatcherservlet من الفئة التجريدية: Frameworkservlet ، ويرث httpservlet بشكل غير مباشر (Frameworkservlet من httpservletbean ، وراث httpservletbean من httpservlet)
تهيئة servlet
void inittstrategies المحمية (ApplicationContext Context) {initMultiParTresolver (Context) ؛ // تحميل الملف والحالة. إذا كان نوع الطلب متعددًا ، فعليك تحميل الملفات وتحليلها من خلال multipartresolver ؛ initlocaleresolver (السياق) ؛ // توطين التحليل initTheMeresolver (السياق) ؛ // تسليم الترفيه inithandlermappings (السياق) ؛ // طلبات رسم الخرائط إلى المعالج InithandlerAdapters (السياق) ؛ // تعيين أنواع متعددة من المعالجات InithandLerexceptionResolvers (السياق) ؛ // دعم أنواع متعددة من المعالجات من خلال المعالج ؛ // إذا تمت مواجهة استثناء أثناء التنفيذ ، فسيتم تسليمه إلى HandleRexceptionResolver لتحليل initRequestTtoviewnametranslator (السياق) ؛ // تحليل الطلب مباشرة إلى اسم العرض initViewResOlvers (Context) ؛ // حل اسم العرض المنطقي إلى العرض المحدد من خلال ViewResolver لتنفيذ initflashMapManager (السياق) ؛ // Flash Map Manager}كيفية التعامل مع الطلبات:
طريقة خدمة Servlet تتعامل مع طلبات HTTP.
تحدد FramoWorkservlet.java الخدمة وتدمير طرق Servlet ، كما هو موضح أدناه:
/** * تجاوز تطبيق الفئة الأصل من أجل اعتراض الطلبات *. */ Override Service Foid Service (طلب httpservletrequest ، استجابة httpservletresponse) يلقي servleTexception ، ioException {string method = request.getMethod () ؛ if (method.equalsignorecase (requestMethod.patch.name ())) {processRequest (request ، response) ؛ } آخر {super.service (طلب ، استجابة) ؛ }}نعلم أن هناك سبعة أنواع من أنواع طلبات HTTP (بالإضافة إلى خيار) ، والتي يتم تعريفها على النحو التالي:
requestmethod {get ، head ، post ، put ، patch ، delete ، الخيارات ، تتبع} خدمة () من Frameworkservlet تتعامل مع طلبات مختلفة. نستخدم المنشورات المشتركة لتوضيح:
/*** قم بمعالجة هذا الطلب ، ونشر حدث بغض النظر عن النتيجة. * <p> يتم تنفيذ معالجة الأحداث الفعلية بواسطة Abstract * {Link #Doservice} طريقة القالب. */ Process ProcessRequest النهائي المحمي (طلب httpservletrequest ، استجابة httpservletresponse) servletexception ، ioException {long starttime = system.currentTimeMillis () ؛ failureCause القابلة للتأثير = فارغة ؛ localecontext previctLocaleContext = localecontextholder.getlocaleContext () ؛ localecontext localecontext = buildlocalecontext (request) ؛ requestAttributes previctArtributes = requestContexTholder.getRequestAtTributes () ؛ servletRequestAttRibutes requestAtTributes = BuildRequestAtTributes (طلب ، استجابة ، سابقات ،) ؛ webasyncmanager asyncmanager = webasyncutils.getAsyncManager (request) ؛ asyncmanager.registerCallableInterceptor (frameworkservlet.class.getName () ، new requestBindingInterceptor ()) ؛ initContextholders (request ، localecontext ، requestAttributes) ؛ حاول {doservice (طلب ، استجابة) ؛ } catch (servleTexception ex) {failureCause = ex ؛ رمي السابقين } catch (ioException ex) {failureCause = ex ؛ رمي السابقين } catch (throwable ex) {failureCause = ex ؛ رمي NETTEDServleTexception ("فشل معالجة الطلب" ، على سبيل المثال) ؛ } أخيرًا {ResetContexTholders (طلب ، previourlocaleContext ، preventattributes) ؛ if (requestAtTributes! = null) {requestAtTributes.requestCompleted () ؛ } if (logger.isdebugenabled ()) {if (failureCause! = null) {this.logger.debug ("لا يمكن إكمال الطلب" ، failureCause) ؛ } آخر {if (asyncmanager.isconCurrentHandlingStarted ()) {logger.debug ("ترك الاستجابة مفتوحة للمعالجة المتزامنة") ؛ } آخر {this.logger.debug ("طلب مكتمل بنجاح") ؛ }}} publishRequestHandleDevent (طلب ، وقت البدء ، FailuRecause) ؛ }} يحدد Frameworkservlet مجردة تدفق المعالجة ، ويتركه للفئات الفرعية لتنفيذ الطريقة ، ويكمل معالجة الطلبات المحددة.
/** * يجب أن تنفذ الفئات الفرعية هذه الطريقة للقيام بعمل معالجة الطلبات ، * تلقي رد اتصال مركزي للحصول على GET ، Post ، PUT و DELETE. * <p> العقد هو نفسه في الأساس بالنسبة إلى أساليب HttPservlet المتفق عليها بشكل شائع. * <p> يعترض هذه الفئة المكالمات لضمان إجراء معالجة الاستثناءات ونشر الحدث. * param request current http request * param response current http response * athrows استثناء في حالة أي نوع من فشل المعالجة * see javax.servlet.http.httpservlet#doget * @seee javax.servlet.http.httpservle استجابة httpservletresponse) يلقي الاستثناء ؛
التنفيذ المحدد هو كما يلي:
/** * يعرض سمات الطلب والمندوبين الخاصة بـ {link #dodispatch} * للإرسال الفعلي. */ Override void void doservice (httpservletrequest request ، httpservletresponse) يلقي الاستثناء {if (logger.isdebugenabled ()) {String resumed = webasyncutils.getasyncmanager (request) .hasconcurrentResult ()؟ "استئناف": "" ؛ logger.debug ("dispatcherservlet باسم" + getServletName () + "" + resumed + "معالجة" + request.getMethod () + "طلب [" + getRequesturi (request) + "]") ؛ } // حافظ على لقطة من سمات الطلب في حالة تضمين ، // لتكون قادرة على استعادة السمات الأصلية بعد التضمين. الخريطة <string ، Object> detributeStEsSnapshot = null ؛ if (webUtils.isInCludErequest (request)) {catritbultEsSnapShot = new hashmap <string ، Object> () ؛ التعداد <؟> attrnames = request.getAttributenames () ؛ بينما (attrnames.hasmoreElements ()) {string attrname = (string) attrnames.nextElement () ؛ if (this.cleanupafterInclude || attrname.startswith ("org.springframework.web.servlet")) }}}} // إتاحة كائنات إطار عمل للمعالجات وعرض الكائنات. طلب request.setAttribute (locale_resolver_attribute ، this.localeresolver) ؛ request.setAttribute (theme_resolver_attribute ، this.themeresolver) ؛ request.setAttribute (theme_source_attribute ، getTheMesource ()) ؛ flashmap inputFlashMap = this.flashMapManager.RetRieVeanDupDate (طلب ، استجابة) ؛ if (inputFlashMap! = null) {request.setAttribute (input_flash_map_attribute ، collections.unmodiFiAbleAp (inputFlashMap)) ؛ } طلب. request.setattribute (flash_map_manager_attribute ، this.flashMapManager) ؛ حاول {dodispatch (طلب ، استجابة) ؛ } أخيرًا {if (webasyncutils.getAsyncManager (request) .isconCurrentHandlingStarted ()) {return ؛ } // استعادة لقطة السمة الأصلية ، في حالة تشمل. if (AttributEsSnapshot! = null) {restoreTRibutesAfterInClude (request ، dentributEsSnapShot) ؛ }}}أبرز ما ، كتنفيذ موزع الطلب:
الوظائف: 1. قم بتوزيع الطلب على المعالج (احصل على علاقة تعيين Servlet بترتيب التكوين) ؛ 2. الاستعلام عن المعالج الأول الذي يمكن معالجته بناءً على المعالجات التي تم تثبيتها بواسطة Servlet ؛ 3. يعرض المعالج معالجة الطلب
/*** معالجة الإرسال الفعلي إلى المعالج. * <p> سيتم الحصول على المعالج من خلال تطبيق معدات Servlet بالترتيب. * سيتم الحصول على المعالج من خلال الاستعلام عن معالجات Servlet المثبتة * للعثور على الأول الذي يدعم فئة المعالج. * <p> يتم التعامل مع جميع أساليب HTTP بهذه الطريقة. الأمر متروك للمعالجات أو المعالجات * أنفسهم لتحديد الأساليب المقبولة. * @param request request http request * param استجابة http current * athrows استثناء في حالة أي نوع من فشل المعالجة */ void void dodispatch (httpservletrequest request ، httpservletponse response) يلقي استثناء {httpservletrequest processedRequest = request ؛ HandleRexecutionChain MedPedHandler = null ؛ Boolean MultireRequestParsed = false ؛ webasyncmanager asyncmanager = webasyncutils.getAsyncManager (request) ؛ حاول {modelandview mv = null ؛ استثناء dispatchException = null ؛ حاول {processedRequest = checkmultipart (request) ؛ multiredrequestparsed = (processedRequest! = request) ؛ // تحديد معالج للطلب الحالي. MedPedHandler = Gethandler (ProcessedRequest) ؛ if (mappedHandler == null || mappedHandler.gethandler () == null) {noHandlerFound (processedRequest ، response) ؛ يعود؛ } // تحديد محول المعالج للطلب الحالي. HandlerAdapter ha = gethandleradapter (mappedHandler.gethandler ()) ؛ // قم بعملية الرأس المعدلة الأخيرة ، إذا كان مدعومًا من قبل المعالج. طريقة السلسلة = request.getMethod () ؛ منطقية isget = "get" .equals (الطريقة) ؛ if (isget || "head" .equals (method)) {long lastModified = ha.getLastModified (request ، mappedHandler.gethandler ()) ؛ if (logger.isdebugenabled ()) {logger.debug ("القيمة المعدلة الأخيرة لـ [" + getRequesturi (request) + "] هي:" + lastModified) ؛ } if (new ServleTwebRequest (request ، response) .CheckNotModified (lastModified) && isget) {return ؛ }} if (new ServleTwebRequest (request ، response) .CheckNotModified (lastModified) && isget) {return ؛ }} if (! mapPedHandler.ApplyPrehandle (ProcessedRequest ، response)) {return ؛ } حاول {// بالفعل استدعاء المعالج. mv = ha.handle (processedRequest ، response ، mappedHandler.gethandler ()) ؛ } أخيرًا {if (asyncmanager.isconcurrentHandlingStarted ()) {return ؛ }} ApplyDefaultViewName (request ، mv) ؛ mediDhandler.applyposthandle (ProcessedRequest ، استجابة ، MV) ؛ } catch (استثناء ex) {dispatchException = ex ؛ } ProcessDispatChResult (ProcessedRequest ، استجابة ، MapPedHandler ، MV ، DispatchException) ؛ } catch (استثناء ex) {triggerafterCompletion (ProcessedRequest ، استجابة ، medpedHandler ، ex) ؛ } catch (error err) {triggerafterCompletionWitherRor (processedRequest ، response ، mappedHandler ، err) ؛ } أخيرًا {if (asyncmanager.isconcurrentHandlingStarted ()) {// بدلاً من postthandle و eftCompletion medderlerler.applyafterCurrentHandlingStarted (ProcessedRequest ، response) ؛ يعود؛ } // تنظيف أي موارد تستخدمها طلب متعدد. if (multiretrequestparsed) {cleanupMultiPart (processedRequest) ؛ }}}تدمير servlet
/*** أغلق webapplicationContext من هذا servlet. * see org.springframework.context.configurableApplicationContext#close () */ Override public void Dorner () {getServletContext (). log ("Dratering Spring Frameworkservlet ' + getServletName () +"' '") ؛ // فقط Call Close () على webapplicationContext إذا تمت إدارتها محليًا ... إذا (this.webapplicationContext easuleof configurableApplicationContext &&! هذا. }}ملخص:
نظرًا لقيود الفصل ، تقدم هذه المقالة فقط عملية معالجة الطلب ولا تجري تحليلًا متعمقًا للرمز. ستبدأ المقالة التالية من التفاصيل وتحليل جمال رمز الربيع.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.