เมื่อเร็ว ๆ นี้ฉันดูซอร์สโค้ดของฤดูใบไม้ผลิและสงสัยว่าฤดูใบไม้ผลิเริ่มต้นอย่างไรโดยไม่ต้องกำหนดค่า web.xml ด้วยความสามารถที่ จำกัด และครั้งแรกที่ฉันอ่านซอร์สโค้ดและโพสต์บล็อกโปรดยกโทษให้ฉันถ้าฉันไม่รู้ว่าจะทำอย่างไร ~
IDE ที่ฉันใช้คือ Intellij Idea ซึ่งง่ายต่อการอ่านซอร์สโค้ดมากกว่า myeclipse และฉันชอบมันมากในพื้นหลังสีดำ จากนั้นโครงการจะทำงานภายใต้ปลั๊กอิน Maven Tomcat7 เวอร์ชันสปริงคือ 4.3.2.- รีลีส
หากคุณเขียนเว็บสปริงที่มีการกำหนดค่าคำอธิบายประกอบบริสุทธิ์คุณควรรู้ว่าคุณต้องสืบทอดคลาสการเริ่มต้นเพื่อโหลดถั่วและจากนั้นฟังก์ชั่นและถั่วที่กำหนดเองของเราจะถูกโหลดจากคลาสนี้ ด้านล่างนี้เป็นหนึ่งในการทำงานของฉัน
@order (1) คลาสสาธารณะ WebMVCinit ขยาย AbstractannotationConfigDispatcherservleTinitializer {คลาสที่ได้รับการป้องกัน <?> [] getRootConfigClasses () {ส่งคืนคลาสใหม่ [] {rootConfig.class, websecurityConfig.class}; } คลาสที่ได้รับการป้องกัน <?> [] getServletConfigClasses () {ส่งคืนคลาสใหม่ [] {webConfig.class}; } สตริงที่ได้รับการป้องกัน [] getServletMappings () {ส่งคืนสตริงใหม่ [] {"/"}; } @Override ตัวกรองป้องกัน [] getServletFilters () {ส่งคืนตัวกรองใหม่ [] {ใหม่ hiddenhttpmethodfilter ()}; -ก่อนอื่นให้ดูที่โครงสร้างของคลาส AbstractannotationConfigDispatcherservletInitializer นี่เป็นฟังก์ชั่น UML ของความคิด คลิกขวาไดอะแกรม-> แสดงไดอะแกรมในชั้นเรียน
จากนั้นเราคลิกโดยตรงที่ AbstractannotationConfigDispatcherservletInitializer คุณจะเห็นว่าคลาสนี้ง่ายมากโดยมีเพียงสี่วิธีเท่านั้น จากนั้นเราให้ความสนใจกับ createrootapplicationContext ()
@Override Protected WebApplicationContext CreaterootapplicationContext () {คลาส <?> [] configClasses = getRootConfigClasses (); if (! ObjectUtils.isEmpty (configclasses)) {AnnotationConfigWebapplicationContext rootAppContext = ใหม่หมายเหตุประกอบใหม่ CONFIGWEBAPPLICANCONTECTINTENTECTION (); rootappcontext.register (configclasses); ส่งคืน rootappcontext; } else {return null; -วิธีนี้หมายถึงการได้รับ rootclasses ที่ส่งโดยผู้ใช้ (โปรแกรมเมอร์) จากนั้นลงทะเบียนถั่ว นี่ไม่ใช่สิ่งที่เรากังวล แต่ควรดำเนินการวิธีนี้หลังจากเริ่มต้นดังนั้นเราจึงสามารถค้นหาจากวิธีนี้
ภายใต้แนวคิด Ctrl+G สามารถค้นหาวิธีการหรือคลาสที่จะโทรจากนั้นตั้งค่าช่วงการค้นหาเป็นโครงการและไลบรารี
เราพบว่าเมธอด registerContextLoadListener (servletContext servletContext) ภายใต้ AbstractContextloaderInitializer เรียก createrootapplicationContext () ของ subclass เพื่อรับ WebApplicationContext และค้นหาผู้โทรของ Methoder registerContexteLoTerListener เป็นผลให้พบว่ามันเป็น onstartup (servletContext servletContext) ภายใต้คลาสนี้ คลาส AbstractContextloaderInitializer มีการโพสต์ด้านล่าง
บทคัดย่อระดับสาธารณะ AbstractContextloaderInitializer ใช้ webApplicationInitializer { / ** logger ที่มีอยู่สำหรับ subclasses* / การป้องกันบันทึกสุดท้ายบันทึกการบันทึก = logfactory.getLog (getClass ()); @Override โมฆะสาธารณะ onStartup (servletContext servletContext) พ่น servletexception {registercontextloaderlistener (servletContext); } /*** ลงทะเบียน {@link contextloaderListener} กับบริบท servlet ที่กำหนด * {@code contextloadLlistener} เริ่มต้นด้วยบริบทแอปพลิเคชันที่ส่งคืน * จาก {@link #createrootapplicationContext ()} วิธีการเทมเพลต * @param servletContext บริบท servlet เพื่อลงทะเบียนผู้ฟังกับ */ void void registercontextloadListener (servletContext servletContext) {webApplicationContext rootAppContext = createrootapplicationContext (); if (rootAppContext! = null) {contextloaderListener listener = new contextloaderListener (rootAppContext); Listener.SetContextInitializers (getRootapplicationContextInitializers ()); ServletContext.addListener (ผู้ฟัง); } else {logger.debug ("ไม่มี contextloaderListener ลงทะเบียนเป็น" + "createrootapplicationContext () ไม่ได้ส่งคืนบริบทแอปพลิเคชัน"); }} /** * สร้างบริบทของแอปพลิเคชัน "<strong> </strong> </strong>" ที่จะให้กับ * {@code contextloaderListener} * <p> บริบทที่ส่งคืนจะถูกมอบหมายให้ * {@link contextloaderListener#contextloaderListener (WebApplicationContext)} และจะถูกสร้างขึ้นเป็นบริบทหลักสำหรับแอปพลิเคชัน {@code dispatcherServlet} ดังนั้นโดยทั่วไปจะมีบริการระดับกลางแหล่งข้อมูล ฯลฯ * @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@code null} หากบริบทรูทไม่ต้องการ * @see org.springframework.web.servlet.support.abstractDiscterservletinitializer /** * ระบุบริบทของแอปพลิเคชันเริ่มต้นที่จะนำไปใช้กับแอปพลิเคชันรูท * บริบทที่ {@code contextloaderListener} กำลังถูกสร้างขึ้นด้วย * @Since 4.2 * @See #CreaterootapplicationContext () * @See ContextLoadLliStener #setContextInitializers */ การป้องกัน ApplicationContextInitializer <?> [] getRootApplicationContextInitializers () {return null; -โปรดทราบว่าเราข้าม AbstractDispatcherservletInitializer คลาสบทคัดย่อ (ดูแผนภาพ UML) คลาสนี้ส่วนใหญ่กำหนดค่า DispatchERServlet ซึ่งเป็นการใช้งานของสปริง MVC และฟังก์ชั่นอื่น ๆ
ถ้าอย่างนั้นใครจะโหลด AbstractContextloaderInitializer WebApplicationInitializer เป็นอินเทอร์เฟซอยู่แล้วและจะไม่มีคลาสนามธรรมที่จะเรียกมัน ดังนั้นฉันจึงพยายามค้นหาอินเตอร์เฟส WebApplicationInitializer เนื่องจากโครงการขนาดใหญ่เช่นฤดูใบไม้ผลินั้นมุ่งเน้นอินเทอร์เฟซแน่นอนการโทรจึงถูกเขียนไปยังอินเทอร์เฟซ จากนั้นเราพบคลาส SpringservletContainerInitializer ซึ่งใช้อินเตอร์เฟส servletContainerInitializer คลาสนี้อาจหมายถึงการเริ่มต้นการใช้งานด้านธุรกิจทั้งหมด อาจกล่าวได้ว่าชั้นเรียนนี้อยู่ใกล้กับเป้าหมายของเรามาก ด้านล่างนี้คือ SpringservletContainerInitializer
@HandLestypes (WebApplicationInitializer.class) คลาสสาธารณะ SpringservletContainerInitializer ใช้ servletContainerInitializer {@Override โมฆะสาธารณะ onstartup (ตั้งค่า <คลาส <? >> webAppinitializerclasses LinkedList <WebApplicationInitializer> (); if (webAppinitializerclasses! = null) {สำหรับ (คลาส <?> waiclass: webappinitializerclasses) {// เป็นการป้องกัน: คอนเทนเนอร์เซิร์ฟเล็ตบางตัวให้คลาสที่ไม่ถูกต้องแก่เรา // ไม่ว่า @handlestypes พูดอะไร ... ถ้า (! WebApplicationInitializer.class.isassignableFrom (Waiclass)) {ลอง {initializers.add ((webapplicationInitializer) waiclass.newinstance ()); } catch (throwable ex) {โยน servletexception ใหม่ ("ล้มเหลวในการสร้างอินสแตนซ์คลาส webapplicationInitializer", ex); }}}}} if (initializers.isEmpty ()) {servletContext.log ("ไม่มีประเภท Spring WebApplicationInitializer ที่ตรวจพบบน classPath"); กลับ; } servletContext.log (initializers.size () + "สปริง webapplicationInitializers ตรวจพบบน classPath"); AnnotationAwareOrderComparator.sort (Initializers); สำหรับ (webApplicationInitializer initializer: initializers) {initializer.onstartup (servletContext); -ใน Foreach ครั้งสุดท้ายเริ่มต้น webapplicationInitializers ทั้งหมด ดังนั้นคำถามคือใครจะเริ่ม SpringservletContainerInitializer ฤดูใบไม้ผลิจะไม่สามารถเริ่มต้นได้ด้วยตัวเอง
ในสภาพแวดล้อมเว็บมีเพียงเว็บคอนเทนเนอร์ เราสามารถสร้างจุดพักได้ในหนึ่งในสถานที่ข้างต้นจากนั้นทำการดีบัก (อันที่จริงเราสามารถแก้ไขข้อบกพร่องได้อย่างสมบูรณ์ = = ตลอดกระบวนการซึ่งแม่นยำและรวดเร็ว แต่สิ่งนี้ขาดความหมายของการค้นหาและทิวทัศน์ตามถนนค่อนข้างดี)
คุณสามารถดูวิธี startInternal ของคลาส StandardContext ภายใต้แพ็คเกจ org.apache.catalina.core สิ่งนี้อยู่ในขอบเขตของ Tomcat ดังนั้นเป้าหมายของเราจึงสำเร็จได้ โปรดทราบว่าอินเทอร์เฟซ servletContainerInitializer ไม่ได้อยู่ภายใต้แพ็คเกจสปริง แต่เป็น javax.servlet
ฉันเดาว่า Tomcat ใช้อินเตอร์เฟส servletContainerInitializer ของ javax.servlet เพื่อค้นหาคลาสที่ใช้อินเทอร์เฟซนี้ในคอนเทนเนอร์จากนั้นโทรหาพวกเขา onstartup แล้ว SpringservletContainerInitializer ทั้งหมดสามารถเริ่มต้น webapplicationInitializers ทั้งหมด นอกจากนี้ความปลอดภัยของสปริงยังได้รับการกำหนดค่าด้วยคำอธิบายประกอบเพื่อใช้งาน WebApplicationInitializer ดังนั้นฤดูใบไม้ผลิจึงขยายได้มาก มาดูซอร์สโค้ด Tomcat ในอีกไม่กี่วันข้างหน้าเพื่อทำความเข้าใจกลไก Tomcat
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น