ภาพรวม
สำหรับนักพัฒนาเว็บโมเดล MVC นั้นคุ้นเคยกับทุกคนมาก ใน SpringMVC คำขอที่ตรงกับเงื่อนไขเข้าสู่ Dispatcherservlet ที่รับผิดชอบในการแจกจ่ายคำขอ dispatcherservlet แมป URL คำขอไปยังคอนโทรลเลอร์ (บันทึกใน handlermapping) ในที่สุด Handlermapping จะส่งคืน HandlerexecutionChain ซึ่งมีตัวจัดการวัตถุประมวลผลเฉพาะ (นั่นคือสิ่งที่เราเขียนเมื่อเราตั้งโปรแกรม) คอนโทรลเลอร์) และชุดของ interceptors ในเวลานี้ Dispatcherservlet จะพบตัวจัดการที่รองรับประเภทโปรเซสเซอร์นี้ตามตัวจัดการในตัวจัดการใน handlerexecutionchain ที่ส่งคืน ในอะแดปเตอร์โปรเซสเซอร์ในที่สุดจะเรียกวิธีการตอบกลับคำขอของคอนโทรลเลอร์และส่งคืนมุมมองผลลัพธ์ (ModelandView) หลังจากได้รับมุมมองผลลัพธ์ผลลัพธ์จะปรากฏขึ้นผ่านวิธีการเรนเดอร์
ระบบมรดก Handermapping:
SpringMVC ร้องขอการแจกจ่ายไปยังตัวประมวลผลตัวจัดการ ขั้นตอนนี้ได้รับการแก้ไขผ่านโมดูล Handlermapping Handlermapping ยังจัดการกับตัวดักจับ
มาดูต้นไม้สืบทอดของ handlermapping ก่อน
คุณสามารถจัดหมวดหมู่ได้อย่างนี้:
1. อินเตอร์เฟส handlermapping กำหนด API: handlerexecutionchain gethandler (คำขอ httpservletrequest) โยนข้อยกเว้น;
2. คลาสนามธรรมพื้นฐาน: ส่วนใหญ่เตรียมสภาพแวดล้อมบริบทให้ตะขอ gethandlerinternal, ห่อหุ้ม interceptor ไปยัง handlerexecutionchain
3. การใช้ @Controller, @requestmapping ตามคำอธิบายประกอบ
4. กำหนดค่า SimpleUrlhandlermapping จาก URL ไปยังตัวจัดการในไฟล์การกำหนดค่า
5. beannameurlhandlermapping ถูกนำมาใช้โดยค่าเริ่มต้น
6. การแม็พของคลาสย่อยคอนโทรลเลอร์
ลองมาดู Handlermapping เพียงแค่ Gethandler API นั้นง่ายมาก
// handlermappingpackage org.springframework.web.servlet; อินเตอร์เฟสสาธารณะ handlermapping {handlerexecutionchain gethandler (คำขอ httpservletrequest) โยนข้อยกเว้น;}} Abstracthandlermapping นั้นไม่ง่ายอย่างนั้น
ก่อนอื่นให้ดูที่คลาสที่สืบทอดโดย abstracthandlermapping และอินเทอร์เฟซที่ใช้
แพ็คเกจ org.springframework.web.servlet.handler; บทคัดย่อระดับนามธรรม Abstracthandlermapping ขยาย WebApplicationObjectSupportImplements handlermapping, สั่ง {// ... } WebApplicationObjectSupport ใช้เพื่อให้บริบท ApplicationContext และ ServletContext
นอกจากนี้ยังมีวิธีการเริ่มต้นที่นี่ซึ่งมักใช้ในอนาคต Abstracthandlermapping ถูกแทนที่โดยตรง
อินเทอร์เฟซ ApplicationContextaware และ ServletContextAware ยังคงใช้งานอยู่ในคลาสหลักและแนวคิดสปริงเป็นแบบครบวงจร
คำสั่งซื้อใช้สำหรับการเรียงลำดับการรวบรวม
ลองดูคุณสมบัติของ abstracthandlermapping ต่อไป
// abstracthandlermapping // คำสั่งซื้อกำหนดค่าสูงสุดและลำดับความสำคัญคือลำดับ INT ส่วนตัวที่เล็กที่สุด = integer.max_value; // ค่าเริ่มต้น: เช่นเดียวกับที่ไม่ได้สั่งซื้อ // ตัวจัดการเริ่มต้น, obejct ที่ใช้ที่นี่และการใช้งาน subclass, ใช้ handlermethod, handlerexecutionchain และวัตถุส่วนตัวอื่น ๆ defaulthandler; // คลาสเสริมสำหรับการคำนวณ urlpather urlpathhelper Antpathmatcher (); // การกำหนดค่า interceptor:, การตั้งค่าคุณสมบัติ handlermapping;, extionInterceptors ตั้งค่ารายการสุดท้ายส่วนตัว <Ojrop> interceptors = arrayList ใหม่ <Ojrop> (); // แยกวิเคราะห์จาก interceptor การจับคู่จะถูกใช้จะถูกใช้รายการสุดท้ายส่วนตัว <MappedInterceptor> mappedInterceptors = new ArrayList <MappedInterceptor> ();
ตรวจสอบการเริ่มต้นของ interceptor:
// abstracthandlermapping@overrideprotected void itapplicationContext () พ่น beansexception {extionInterceptors (this.interceptors); detectmappedinterceptors (สิ่งนี้ mappedinterceptors); interceptors ()}/*** {}/*** สแกน mappedinterceptors ภายใต้แอปพลิเคชันและเพิ่มลงใน mappedinterceptors*/void detectmappedinterceptors (รายการ <mapedinterceptor> mappedinterceptors) {mapedinterceptors.addall FALSE) .values ());}/*** รวบรวม mappedInterceptor และปรับให้เข้ากับ handlerInterceptor และ webRequestInterceptor*/void itinterceptors () {ถ้า (! this.interceptors.isempty () {สำหรับ (int i =; i <this.interceptors.size () NULL) {โยน ungloralArgumentException ใหม่ ("หมายเลขรายการ" + i + "ในอาร์เรย์ interceptors เป็น null");} ถ้า (อินสแตนซ์ interceptor ของ mappedinterceptor) {mappedinterceptors.add ((mapedinterceptor) interceptor); AdaptInmentceptor (Object Interceptor) {if (Interceptor Instanceof HandlerInterceptor) {return (handlerInterceptor) interceptor;} อื่นถ้า (interceptor instanceof webrequestinterceptor) {ส่งคืน webrequesthandlowerceptoradapter (webRequestInterceptor) interceptor.getClass (). getName ());}}จากนั้นมีการดำเนินการของ Gethandler (คำขอ httpservletrequest) และที่นี่ยังขอสงวน GethandlerInternal (คำขอ httpservletrequest) สำหรับการใช้งาน subclass
// abstracthandlermappingpublic สุดท้าย handlerexecutionchain gethandler (httpservletrequest คำขอ) โยนข้อยกเว้น {วัตถุ handler = gethandlerinternal (คำขอ); ถ้า (handler == null) {handler = getDefaulthandler () string อินสแตนซ์) {String handlerName = (String) Handler; handler = getApplicationContext (). getBean (handlername);} ส่งคืน gethandlerexecutionchain (ตัวจัดการ, คำขอ); ในที่สุดก็ห่อหุ้ม interceptor ไปยัง handlerexecutionchain
เพิ่ม AdaptedInterceptors โดยตรง
mappedinterceptors จะต้องเพิ่มหลังจากจับคู่ตาม URL
// abstracthandlermapping ที่ได้รับการป้องกัน handlerexecutionchain gethandlerexecutionchain (ตัวจัดการวัตถุ, คำขอ httpservletrequest) {handlerexecutionchain chain = (handler อินสแตนซ์ของ handlerexecutionchain) ตัวจัดการ: handlerexecutionchain (handler); chain.addinterceptors (getAdaptedInterceptors ()); String lookuppath = urlPathHelper.getLookuppathForRequest (คำขอ); สำหรับ (mappedInterceptor mappedinterceptor: mapedinterceptors) {ถ้า (mapedinterceptor.matches {chain.addinterceptor (mappedInterceptor.getInterceptor ());}} return chain;} การแม็พของคลาสย่อยคอนโทรลเลอร์สาขานี้ดูการสืบทอดคลาสก่อน
มาพูดคุยเกี่ยวกับความรับผิดชอบหลักของแต่ละหมวดหมู่ที่นี่
1. Abstracthandlermapping เตรียมสภาพแวดล้อมบริบท จัดเตรียมตะขอ gethandlerinternal; ห่อหุ้ม interceptor ไปยัง handlerexecutionchain
2. Abstracturlhandlermapping ใช้วิธีการลงทะเบียนตัวจัดการสำหรับการใช้งาน subclass; ใช้ GethandlerInternal และค้นหาตัวจัดการตามข้อมูลการกำหนดค่าที่เริ่มต้นโดยคลาสย่อย
3. AbstractDetectingUrlHandlerMapping สแกนวัตถุภายใต้แอปพลิเคชันและหลังจากการวนซ้ำให้วิธีการขอเบ็ดกำหนดว่าจะกำหนดวิธีการกรอง
4. AbstractControllerUrlHandlerMapping Onprements DENURLSFORHANDLER เพิ่มการดำเนินการของตัวจัดการ (การกำหนดค่าไฟล์การกำหนดค่า) และขอสงวนวิธีการ Hook BuildurlSforHandler สำหรับการใช้งาน subclass; ในขณะเดียวกันก็ตัดสินคลาสย่อยของคอนโทรลเลอร์
5. ControllerBeanNameHandlermapping สร้าง URL ตามชื่อถั่ว
ControlerClassNameHandlerMapping สร้าง URL ตามชื่อคลาส
เริ่มต้นด้วย Abstracturlhandlermapping ที่นี่เราแค่ดูรหัสประมาณ หากคุณต้องการวิเคราะห์อย่างรอบคอบโปรดย้ายไปที่ <SpringMVC การตีความซอร์สโค้ด - การตีความ - HandlerMapping - AbstractUrlhandLermapping Series Series Distribution>
การลงทะเบียนของ Handler
Void registerhandler ที่ได้รับการป้องกัน (String [] urlpaths, String beanname) พ่น beansexception, unglemalstateexception {} void registerhandler ที่ได้รับการป้องกัน การค้นหาตัวจัดการ
วัตถุที่ได้รับการป้องกัน gethandlerInternal (คำขอ httpservletrequest) พ่นข้อยกเว้น {} // ค้นหา handlerprotected object lookuphandler (สตริง urlpath, httpservletrequest คำขอ) โยนข้อยกเว้น {} // ตรวจสอบ handlerprotected Handlerexecutionchainprotected Object BuildPathexpositingHandler (Object RawHandler, String BestMatchingPattern, String PathWithInmapping, MAP <String, String> UriteMplateVariables) {}AbstractDetectingUrlHandlermapping นี่ไม่ได้ขยายออกไปโปรดย้ายในรายละเอียด <SpringMVC การตีความซอร์สโค้ด - HandlerMapping - AbstractDetectingUrlHandLermapping ชุดค่าเริ่มต้น
จะทำอย่างไร:
1. โทร detecthandlers เพื่อสแกน objct โดยการเขียนทับ itapplicationContext
2. ให้วิธีการตะขอกำหนดค่าใช้จ่ายในการสร้าง URL subclass ตามตัวจัดการตามตัวจัดการ
3. โทร RegisterHandler ของคลาสแม่เพื่อลงทะเบียน
@OverridePublic เป็นโมฆะ itapplicationContext () พ่น ApplicationContextexception {super.initapplicationContext (); detecthandlers ();} void detecthandlers ที่ได้รับการป้องกัน () พ่น {// ... }/*** AbstractControllerUrlHandlermapping นี่ไม่ได้ขยายออกไปโปรดย้ายในรายละเอียด <SpringMVC การตีความซอร์สโค้ด - HandlerMapping - AbstractDetectingUrlHandLermapping ชุดค่าเริ่มต้น สิ่งที่ต้องทำโดยเฉพาะ
1. เขียนทับ encurlsforhandler เพื่อเพิ่มตรรกะเพื่อลบคลาสบางคลาสและใช้คลาส ExcludedClasses และ ExpludedPackages ที่กำหนดค่าไว้ในไฟล์การกำหนดค่า
2. ตรวจสอบว่าคลาสย่อยของคอนโทรลเลอร์
3. สำรอง buildurlsforhandler เพื่อสร้าง URL สำหรับคลาสย่อย
@OverrideProtected String [] MENURLSFORHANDLER (String BeanName) {คลาส beanClass = getApplicationContext (). getType (BeanName); ถ้า (isElivelyformapping (beanname, beanclass) BeanName, คลาส BeanClass) {} บูลีนที่ได้รับการป้องกัน ISControllerType (คลาส BeanClass) {} สตริงบทคัดย่อที่ได้รับการป้องกัน [] Buildurlsforhandler (String Beanname, คลาส BeanClass); ControllerBeanNameHandLermapping และ ControlLerClassNameHandLermapping ดูที่ซอร์สโค้ดโดยตรงหรือย้ายไปที่ <SpringMVC การตีความรหัสซอร์ส SimpleUrlHandlerMapping กำหนดค่า URL โดยตรงไปยังตัวจัดการในไฟล์การกำหนดค่าซึ่งคือการใช้ registerHandlers เพื่อลงทะเบียนตัวจัดการในเอกสารการกำหนดค่าอ่านรหัสโดยตรงหรือย้าย <SpringMVC การตีความซอร์สโค้ด
beannameurlhandlermapping ดำเนินการกำหนด urlsforhandler เพื่อสร้าง URL ดูรหัสโดยตรงหรือย้าย <SpringMVC การตีความซอร์สโค้ด - การตีความ - handlermapping - การเริ่มต้นชุดการเริ่มต้นชุด
ใช้ @Controller, @requestmapping ตามคำอธิบายประกอบ
กระดูกที่ยากที่สุด
มาดูมรดกของชั้นเรียนก่อน
มาพูดคุยเกี่ยวกับความรับผิดชอบของแต่ละหมวดหมู่ สำหรับการวิเคราะห์เฉพาะโปรดย้ายไปยังบทความต่อไปนี้
<การตีความซอร์สโค้ดซอร์สโค้ด SpringMVC - HandlerMapping - RequestMappingHandLermapping Initialization>
<การตีความซอร์สโค้ดซอร์สโค้ด SpringMVC - HandlerMapping - การแจกจ่ายการร้องขอการร้องขอการร้องขอ
1. AbstracthandLermethodmaping กำหนดกระบวนการเริ่มต้นและวิธีการทำแผนที่เมื่อร้องขอ
การเริ่มต้น:
1.1.1 สแกนวัตถุภายใต้แอปพลิเคชัน
1.1.2 สำรองเมธอด Ishandler Hook เพื่อพิจารณาว่าวัตถุนั้นเป็นตัวจัดการว่าวัตถุนั้น
1.1.3 สแกนแต่ละตัวจัดการซ้ำ ๆ เพื่อค้นหาวิธีการที่ตรงตามข้อกำหนด คำพิพากษาที่นี่ยังคงเหลืออยู่ในคลาสย่อยเพื่อใช้งาน getMappingFormethod
1.1.4 เมื่อลงทะเบียนโปรเซสเซอร์ที่พบคุณจะต้องตรวจสอบให้แน่ใจว่าการร้องขอเงื่อนไขการจับคู่การทำ MappingInfo สามารถแมปกับตัวจัดการได้เท่านั้น
1.1.5 รับ URL ตามเงื่อนไขการจับคู่และสิ่งเดียวกันก็เป็นเพียงการกำหนดกระบวนการ อัลกอริทึมเฉพาะถูกทิ้งไว้ในคลาสย่อยเพื่อใช้งาน getMappingPathPatterns
ขอการประมวลผลการกระจาย:
1.2.1 วิธีการจับคู่สตริงโดยตรงค้นหาตัวจัดการ
1.2.2 การค้นหาเงื่อนไขการจับคู่อัลกอริทึมเฉพาะที่นี่จะถูกส่งไปยังคลาสย่อยเพื่อ getMatchingMapping
1.2.3 เรียงลำดับและรับตัวจัดการการจับคู่ที่ดีที่สุด วิธีการเรียงลำดับที่นี่ยังคงเป็นการประมวลผล subclass getMappingconparator
1.2.4 การห่อหุ้มการจับคู่และไม่จับคู่ตัวจัดการตามลำดับ
2. requestmappinginfohandlermapping ใช้ requestmappinginfo เพื่อใช้เงื่อนไขการจับคู่และการเริ่มต้นของ requestmappinginfo จะถูกทิ้งไว้ที่ subclass
2.1 สร้าง URL -> getMappingPathPatterns ตาม requestMappingInfo
2.2 ค้นหาตัวจัดการโดยใช้เงื่อนไขการจับคู่ -> getMatchingMapping
2.3 อัลกอริทึมเปรียบเทียบ -> getMappingComparator
2.4 เขียนทับ HandleMatch และ Cache n ข้อมูลหลายข้อมูลที่จะร้องขอ
รูปแบบการลงทะเบียน, รูปแบบการจับคู่ที่ดีที่สุด, พารามิเตอร์ที่แยกวิเคราะห์ใน URL, พารามิเตอร์หลายค่าที่แยกวิเคราะห์ใน URL, MediaType
2.1.5 Handlernomatch ที่เขียนทับพยายามจับคู่อีกครั้งหลังจากการต่อสู้ครั้งสุดท้าย
3. requestmappinghandlermapping สร้าง requestmappinginfo ตามคำอธิบายประกอบ @controller @requestmapping และตรวจสอบ ishandler
3.1 เขียนทับ AfterPropertIesset และเพิ่มไฟล์ต่อท้ายเพื่อตัดสิน
3.2 ใช้ ISHANDLER และหนึ่งในคำอธิบายประกอบในชั้นเรียนนั้นถูกต้อง
3.3 วิเคราะห์เนื้อหาคำอธิบายประกอบและสร้างอินสแตนซ์ requestmappinginfo