في الآونة الأخيرة ، نظرت إلى رمز الربيع المصدري وتساءلت فجأة كيف بدأ Spring الخاص به دون تكوين Web.xML. بالنظر إلى القدرة المحدودة والمرة الأولى التي قرأت رمز المصدر ونشرت مدونة ، يرجى تسامحني إذا كنت لا أعرف ماذا أفعل ~
IDE IDE IS IDENT IDEA ، والتي من الأسهل قراءة الكود المصدرية من Myeclipse ، وأنا أحبها كثيرًا في الخلفية السوداء. ثم يتم تشغيل المشروع تحت البرنامج المساعد Maven Tomcat7. إصدار الربيع هو 4.3.2.release.
إذا كنت قد كتبت شبكة ربيع مع تكوين التعليق التوضيحي الخالص ، فيجب أن تعلم أنك تحتاج إلى ورث فئة تهيئة لتحميل الفول ، ثم سيتم تحميل وظائفنا والفاصوليا المخصصة من هذه الفئة. فيما يلي أحد أجهزة الويب الخاصة بي
@order (1) فئة عامة webmvcinit يمتد ملخص agrussantationConfigDispatcherservleTinitializer {الفئة المحمية <؟> [] getRootConfigClasses () {return class [] {rootconfig.class ، websecurityconfig.class} ؛ } الفئة المحمية <؟> [] getServletConfigClasses () {return class [] {webConfig.class} ؛ } سلسلة محمية [] getSerVletMappings () {return new string [] {"/"} ؛ } override filter المحمية [] getServletFilters () {return new filter [] {new HiddenHttpMethodFilter ()} ؛ }}أولاً ، انظر إلى بنية فئة AbstractAntAntationConfigDispatcherservletinitializer. هذه هي أيضا وظيفة UML من الفكرة. انقر بزر الماوس الأيمن فوق المخططات-> إظهار المخططات في الفصل.
ثم نضغط مباشرة على AbstractAntAntationConfigDispatcherservleTinitializer. يمكنك أن ترى أن هذا الفصل بسيط للغاية ، مع أربع طرق فقط. ثم نولي اهتماما ل createrootapplicationContext ()
OverRide محمي WebApplicationContext createrOtApplicationContext () {class <؟> [] configclasses = getRootConfigClasses () ؛ if (! objectUtils.isempty (configclasses)) {enrotationConfigWebPlicationContext rootAppContext = New endationConfigWebapplicationContext () ؛ ROOTAppContext.register (configClasses) ؛ إرجاع rootappcontext ؛ } آخر {return null ؛ }}تعني هذه الطريقة تقريبًا الحصول على النطاقات الجذرية التي أرسلها المستخدم (المبرمج) ثم تسجيل الفاصوليا. هذه ليست ما نشعر به ، ولكن يجب تنفيذ هذه الطريقة بعد بدء التشغيل ، حتى نتمكن من البحث عن هذه الطريقة
تحت IDEA ، يمكن لـ Ctrl+G العثور على طريقة أو فئة للاتصال ، ثم تعيين نطاق البحث على المشروع والمكتبة
لقد وجدنا أن طريقة registerContextLoaderListener (ServletContext ServletContext) ضمن AbstractContextLoaderInitializer تستدعي createrootapplicationContext () من الفئة الفرعية للحصول على طريقة webapplicationContext ، والمتابعة للعثور على المتصل الخاص بـ RecordContextLoaderListener (servletxtxt servletxt). نتيجة لذلك ، وجد أنه OnStartup (servletContext ServletContext) ضمن هذا الفئة. تم نشر فئة AbstractContextLoaderInitializer أدناه.
Public Abstract Class AbstractContextLoaderInitializer تنفذ webapplicationInitializer { / ** logger متاح للمسارات الفرعية* / logger النهائي المحمي = logfactory.getlog (getClass ()) ؛ Override public void onStartup (servletcontext servletcontext) يلقي servletexception {registerContextLoaderListener (servletContext) ؛ } /*** قم بتسجيل {link contextloaderListener} مقابل سياق servlet المحدد. تتم تهيئة * {code contextLoaderListener} باستخدام سياق التطبيق الذي تم إرجاعه * من طريقة {link #createRootApplicationContext ()}. * param servletContext سياق servlet لتسجيل المستمع مقابل */ void void registerContextListener (servletcontext servletcontext) {webapplicationContext RootAppContext = createrootapplicationContext () ؛ if (rootAppContext! = null) {contextloaderListener leader = new ContextLoaderListener (rootAppContext) ؛ مستمع. servletContext.addListener (مستمع) ؛ } else {logger.debug ("no contextloaderListener مسجل ، مثل" + "createrootApplicationContext () لم يرد على سياق التطبيق") ؛ }} /** * قم بإنشاء سياق التطبيق "<strong> root </strong>" ليتم توفيره إلى * {code contextLoaderListener}. * <p> يتم تفويض السياق الذي تم إرجاعه إلى * {link contextLoaderListener#contextLoaderListener (webapplicationContext)} وسيتم تأسيسه كسياق الأصل لأي تطبيق {code dispatcherservlet}. على هذا النحو ، فإنه يحتوي عادةً على خدمات من الدرجة المتوسطة ، ومصادر البيانات ، إلخ. /** * حدد أخصائيات سياق التطبيق المراد تطبيقه على تطبيق الجذر * السياق الذي يجري إنشاء {code contextLoaderListener}. * since 4.2 * seee #createOtapplicationContext () * seee contextLoaderListener #setContextInitializers */ محمية ApplicationContextInitializer <؟ }}لاحظ أننا تخطينا فئة AbstractDispatcherservleTinitializer Abstract (انظر مخطط UML). تقوم هذه الفئة بشكل أساسي بتكوين Dispatcherservlet ، وهو تنفيذ SPRING MVC وغيرها من الوظائف.
ثم من سيقوم بتحميل AbstractContextLoaderInitializer؟ WebApplicationInitializer هي بالفعل واجهة ، ولن يكون هناك فئة مجردة للاتصال بها. لذلك حاولت البحث في واجهة webapplicationInitializer. نظرًا لأن المشاريع الكبيرة مثل الربيع موجهة نحو الواجهة ، تتم كتابة المكالمة بشكل عام إلى الواجهة. ثم وجدنا فئة SpringservletContainerInitializer ، والتي تنفذ واجهة ServletContainerInitializer. ربما تعني هذه الفئة بدءًا من جميع أجهزة WebApplicationInitializers. يمكن القول أن هذا الفصل قريب جدًا من هدفنا. أدناه هو SpringservletContainerInitializer
HandLestypes (webapplicationInitializer.class) public class SpringServletContainerInitializer تنفذ servletContainerInitializer {Override public void onStartup LinkedList <AbplicationInitializer> () ؛ إذا (webappinitializerClasses! = null) {for (class <؟> waiclass: webappinitializerClasses) {// كن دفاعيًا: بعض حاويات servlet تزودنا بفئات غير صالحة ، // لا يهم ما يقوله Handlestypes ... if (! waiclass.isinterface () &&! webapplicationInitializer.class.isAssignableFrom (waiclass)) {try {initializers.add ((webapplicationInitializer) waiclass.newinstance ()) ؛ } catch (throwable ex) {رمي ServleTexception جديد ("فشل في إنشاء إنشاء فئة webapplicationInitializer" ، ex) ؛ }}}}} if (initializers.isempty ()) {servletContext.log ("لا توجد أنواع Spring webapplicationInitializer المكتشفة على classpath") ؛ يعود؛ } servletContext.log (initializers.size () + "Spring webapplicationInitializers المكتشفة على classpath") ؛ التعليقات التوضيحية. لـ (webapplicationInitializer Entiralizer: initializers) {tirtplizer.onstartup (servletContext) ؛ }}}في آخر foreach ، ابدأ جميع webapplicationInitializers. لذا فإن السؤال هو ، من سيبدأ SpringservletContainerInitializer؟ من المؤكد أن الربيع لن يكون قادرًا على البدء في حد ذاته.
في بيئة الويب ، لا يوجد سوى حاويات ويب. يمكننا أن نجعل نقطة انقطاع في أحد الأماكن المذكورة أعلاه ثم تصحيحها (في الواقع ، يمكننا التصحيح تمامًا = = طوال العملية ، وهو دقيق وسريع ، لكن هذا يفتقر إلى معنى البحث ، والمشهد على طول الطريق جيد جدًا)
يمكنك رؤية طريقة startInternal لفئة StandardContext تحت الحزمة org.apache.catalina.core. هذا بالفعل في نطاق Tomcat ، لذلك تم تحقيق هدفنا. لاحظ أن واجهة ServletContainerInitializer ليست تحت حزمة الربيع ، ولكن Javax.Servlet
أعتقد أن Tomcat يستخدم واجهة ServletContainerInitializer لـ javax.servlet للعثور على الفصول التي تنفذ هذه الواجهة في الحاوية ، ثم استدعاء onStartup ، ثم يمكن لـ SpringservlevletContainerInitializer البدء في جميع أجهزة WebapplicationInitializers ، والتي تحتوي على Webinitizizer التي كتبناها. بالإضافة إلى ذلك ، يتم تكوين أمان Spring أيضًا مع التعليقات التوضيحية لتنفيذ WebApplicationInitializer ، لذلك Spring يمكن توسيعه للغاية. دعونا نلقي نظرة على رمز مصدر Tomcat في الأيام القليلة المقبلة لفهم آلية Tomcat.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.