مقدمة
تقدم هذه المقالة بشكل أساسي المحتوى ذي الصلة حول عملية بدء تشغيل Servlet والمبادئ في Spring Boot. لن أقول الكثير أدناه ، دعنا نلقي نظرة على المقدمة التفصيلية معًا.
عملية بدء التشغيل والمبادئ:
1 طريقة تشغيل تطبيق التمهيد الربيع
ساعة توقيت ساعة توقيت = ساعة توقيت جديدة () ؛ توقيت. ستارت () ؛ configurableApplicationContext context = null ؛ alualureanalyzers محللون = فارغ ؛ ConfigureDheadlessProperty () ؛ springapplicationRunlisteners المستمعين = getRunListeners (args) ؛ المستمعين. العمل () ؛ جرب {ApplicationArguments ApplicationArguments = defaultApplicationArguments (args) ؛ بيئة البيئة القابلة للتكوين = إعداد البيئة (المستمعين ، ApplicationArguments) ؛ Banner printedbanner = printbanner (البيئة) ؛ // إنشاء سياق حاوية ApplicationContext = createApplicationContext () ؛ المحللون = New FailureAnalyzers (السياق) ؛ PrepareContext (السياق ، البيئة ، المستمعين ، ApplicationArguments ، printedbanner) ؛ // تحديث IOC Container RefreshContext (السياق) ؛ Afterrefresh (السياق ، ApplicationArguments) ؛ المستمعين. ساعة توقيت. stop () ؛ if (this.logstartupinfo) {new StartupInfologger (this.mainapplicationClass) .logStarted (getApplicationLog () ، stalpwatch) ؛ سياق الإرجاع ؛ } catch (throwable ex) {handlerunfailure (السياق ، المستمعون ، المحللون ، ex) ؛ رمي الجديد غير القانوني stateException (ex) ؛ }2 CreateApplicationContext (): إنشاء حاوية IOC. إذا كان تطبيق ويب ، فقم بإنشاء حاوية IOC من annotationConfigemBedDedWebapplication. إذا لم يكن الأمر كذلك ، فقم بإنشاء حاوية IOC من التعليقات التوضيحية.
السلسلة النهائية الثابتة العامة default_context_class = "org.springframework.context." + "annotation.annotationConfigPlicationContext" ؛ /** * اسم فئة سياق التطبيق الذي سيتم استخدامه افتراضيًا لبيئات الويب *. */ السلسلة النهائية الثابتة العامة default_web_context_class = "org.springframework." + "boot.context.embedded.annotationConfigemDedDedWebapplicationContext" ؛ configurableApplicationContext CreateApplicationContext () {class <؟ if (contextClass == null) {try {// إنشاء حاويات IOC مختلفة وفقًا لبيئة التطبيق contextClass = class.forname (this.webenvironment؟ default_web_context_class: default_context_class) ؛ } catch (classnotfoundException ex) {رمي جديد غير aluvalstateException ("غير قادر على إنشاء تطبيق applicationcontext افتراضي ،" + "يرجى تحديد ApplicationContextClass" ، ex) ؛ }} return (configurableApplicationContext) BeanUtils.instantiate (contextClass) ؛ }3 RefreshContext (Context) SPRING BOOT تحديث حاوية IOC (قم بإنشاء كائنات حاوية ، وتهيئة الحاوية ، وإنشاء كل مكون من الحاوية)
private void refreshContext (configurableApplicationContext Context) {Refresh (Context) ؛ if (this.registerShutDownHook) {try {context.registerShutDownHook () ؛ } catch (AccessControlexception ex) {// غير مسموح به في بعض البيئات. }}}}4 تحديث (سياق) ؛ قم بتحديث حاوية IOC التي قمت بإنشائها للتو
تحديث باطل محمي (ApplicationContext ApplicationContext) {Assert.isinstanceof (AbstractapplicationContext.class ، ApplicationContext) ؛ ((AbstractApplicationContext) ApplicationContext) .refresh () ؛ }5. استدعاء طريقة التحديث () الفئة الأصل
public void refresh () يلقي beansexception ، alfarkalStateException {object var1 = this.startupshutdownitor ؛ synchronized (this.startupShutDownItor) {this.preparerefresh () ؛ configurableListableBeanfactory beanfactory = this.obtainfreshbeanfactory () ؛ هذا. جرب {this.postProcessBeanFactory (beanfactory) ؛ this.invokebeanfactorypostprocessors (Beanfactory) ؛ this.registerBeanPostProcessors (beanfactory) ؛ this.initmessagesource () ؛ this.initapplicationEventMulticaster () ؛ this.onrefresh () ؛ this.registerListeners () ؛ هذا. this.finishrefresh () ؛ } catch (beansexception var9) {if (this.logger.iswarnenabled ()) {this.logger.warn ("استثناء تمت مواجهته أثناء تهيئة السياق - إلغاء محاولة التحديث:" + var9) ؛ } this.destroybeans () ؛ this.cancelrefresh (var9) ؛ رمي var9 ؛ } أخيرًا {this.resetCommonCaches () ؛ }}}6 طريقة onrefresh من الفئة الفرعية embedwebapplicationContex
Override محمي void onrefresh () {super.onrefresh () ؛ حاول {createMbedDedServletContainer () ؛ } catch (throwable ex) {رمي ApplicationContextexception ("غير قادر على بدء حاوية مضمنة" ، ex) ؛ }}7 في CreateMedDedServletContainer ، سيتم الحصول على مصنع حاوية Servlet المدمج ، ويتم إنشاء servlet من مصنع الحاوية
private void createMbedDedServletContainer () {inmbedservletcontainer localContainer = this.embeddedServletContainer ؛ servletContext alcalservletcontext = getServletContext () ؛ if (localContainer == null && alcalservletcontext == null) {// الحصول على مصنع حاوية servlet المضمنة insermedServletContainerFactory ContainerFactory = getEmbedDedServletContainerFactory () ؛ // احصل على حاوية servlet المضمنة المقابلة بناءً على مصنع الحاويات this.embeddedServletContainer = ContainerFactory .getemBedDedServletContainer (getselfinitializer ()) ؛ } if if (alcalservletcontext! = null) {try {getselfinitializer (). onStartup (localservletcontext) ؛ } catch (servleTexception ex) {رمي ApplicationContextexception ("لا يمكن تهيئة سياق servlet" ، ex) ؛ }} InitPropertySources () ؛ }8 احصل على مصنع حاوية Servlet من حاوية IOC
. .getBeanNamesfortype (inserdedServletContainerFactory.Class) ؛ if (beannames.length == 0) {رمي ApplicationContextexception جديد ("غير قادر على البدء في embedwebapplicationContext بسبب مفقود" + "embeddedServletContainerFactory Bean.") ؛ } if (beannames.length> 1) {رمي ApplicationContextexception ("غير قادر على بدء تشغيل insumbedWebapplicationContext بسبب متعددة" + "embeddedServletContainerfactory Beans:" + StringUtils.arrayTocommadElimitedString (Beannames)) ؛ } return getBeanfactory (). getBean (Beannames [0] ، inmbedservletcontainerfactory.class) ؛ }9 استخدم مصنع Servlet Container للحصول على حاويات Servlet المضمنة. يعتمد مصنع الحاويات الذي يجب استخدامه على تبعية بيئة التكوين
this.embeddedServletContainer = حاوية.
10 تبدأ عملية الإنشاء أعلاه أولاً في حاوية IOC ، ثم تبدأ حاوية Servlet المدمجة ، ثم تسترجع الكائنات المتبقية التي لم يتم إنشاؤها في حاوية IOC ، مثل وحدة التحكم التي أنشأتها بنفسك.
// instantiate جميع المفردات المتبقية (غير الباطنية). الانتهاء من beanfactoryinitialization (beanfactory) ؛
محمي باطل الانتهاء من beanfactoryinitialization (configurableListableBeanfactory Beanfactory) {// تهيئة خدمة التحويل لهذا السياق. if (beanfactory.containsbean (conversion_service_bean_name) && beanfactory.istypematch (conversion_service_bean_name ، conversionService.Class)) } // قم بتسجيل محلول قيمة مضمن افتراضي إذا لم يتم تسجيل أي ما بعد المعالج // (مثل PropertyPlaceholderConfigurer Bean) أيًا قبل: // في هذه المرحلة ، في المقام الأول للحصول على قرار في قيم سمات التعليقات التوضيحية. if (! beanfactory.hasembeddedvalueresolver ()) {beanfactory.addembeddedvalueresolver (new StringValueresolver () {verride public string resolvestringvalue (String strval) {return getenvironment (). } // تهيئة LoadTimeWeaveraware Beans مبكرًا للسماح بتسجيل محولاتها مبكرًا. String [] weaverawarenames = beanfactory.getBeanNamesfortype (loadtimeweaveraware.class ، false ، false) ؛ لـ (String WeaveraWarename: Weaverawarenames) {getBean (WeaveraWarename) ؛ } // توقف عن استخدام جهاز تحميل الفئة المؤقت لمطابقة النوع. Beanfactory.SettEmpClassloader (NULL) ؛ // السماح بتخزين كل بيانات تعريف تعريف تعريف الفول ، ولا تتوقع المزيد من التغييرات. beanfactory.freezeConfiguration () ؛ // instantiate جميع المفردات المتبقية (غير الباطنية). Beanfactory.preinstantiateseNtons () ؛ }تحقق من طريقة preinstantiatesingletons
prevoid preinstantiatesingletons () يلقي beansexception {if (this.logger.isdeBugenabled ()) {this.logger.debug ("المفرد المسبق في" + this) ؛ } قائمة <Tring> beannames = new ArrayList (this.beanDefinitionNames) ؛ iterator var2 = beannames.iterator () ؛ بينما (صحيح) {بينما (صحيح) {String Beanname ؛ ROOTBEANDEFINITION BD ؛ do {do {do {if (! var2.hasnext ()) {var2 = beannames.iterator () ؛ بينما (var2.hasnext ()) {beanname = (string) var2.next () ؛ كائن singletoninstance = this.getsingleton (beanname) ؛ إذا كان (مثيل Singletoninstance لـ SmartInitializingsingleton) {Final SmartInitializingsingleton SmartSingleton = (SmartInitializingsingleton) Singletoninstance ؛ if (system.getSecurityManager ()! = null) {accessController.doprivileged (new terilegedageAction <Object> () {public object run () {smartsingleton.aftersingletonsinstantiveive () ؛ return null ؛} ، this.getAccessControlContxt ()) ؛ } آخر {smartsingleton.aftersingletonsinStantAnted () ؛ } } يعود؛ } beanname = (string) var2.next () ؛ bd = this.getmergedLocalBeanDefinition (beanname) ؛ } بينما (bd.isabstract ()) ؛ } بينما (! bd.issingleton ()) ؛ } بينما (bd.islazyinit ()) ؛ if (this.isfactorybean (beanname)) {Final Factorybean <؟> factory = (factorybean) this.getBean ("&" + beanname) ؛ منطقية iseagerinit ؛ if (system.getSecurityManager ()!! = null && مصنع مثيل SmartFactoryBean) {iseAgerInit = ((Boolean) AccessController.doprivileged (new terilegedageAction <Ololean> () this.getAccessControlContext ())). BooleAnvalue () ؛ } آخر {iseAgerInit = مصنع من SmartFactoryBean && ((SmartFactoryBean) Factory) .iseAgerInit () ؛ } if (iseAgerInit) {this.getBean (beanname) ؛ }} else {// register bean this.getBean (beanname) ؛ }}}}}}}}}}استخدم طريقة getBean لإنشاء جميع الحالات غير المنشأة من خلال التفكير.
باستخدام حاويات servlet المدمجة:
المزايا: بسيطة ، محمولة
العيوب: JSP لا يدعم افتراضيًا ، والتحسين والتخصيص أكثر تعقيدًا
خطوات لاستخدام حاوية servlet خارجية:
1. يجب إنشاء مشروع الحرب ، ويحتاج بنية دليل مشروع الويب Jianhao.
2 نطاق التبعية المدمجة Tomcat يحدد المقدمة
3 اكتب فئة فرعية من فئة springbootservletinitializer وتجاوز طريقة التكوين
يمتد ServleTinitializer من الدرجة العامة springbootservletinitializer {Override محمية springapplicationbuilder تكوين (تطبيق springapplicationBuilder) {return application.sources (SpringBoot04WebjSpapplication.class) ؛ }}4 ابدأ الخادم
الفرق بين بدء حزمة الجرة وحزمة الحرب
حزمة جرة: قم بتنفيذ طريقة تشغيل springbootapplication ، وابدأ حاوية IOC ، ثم إنشاء حاوية servlet مضمنة
حزمة الحرب: أولاً ، ابدأ خادم Servlet ، ويبدأ الخادم تطبيق SpringBoot (SpringBootServleTinitizer) ، ثم يبدأ حاوية IOC
قواعد Servlet 3.0+
1. بدء تشغيل الخادم (بدء تشغيل تطبيق الويب) ، سيتم إنشاء مثيل ServletContainerLnitializer في جميع حزم JAR في تطبيق الويب الحالي.
2 يتم وضع تطبيق ServletContainerInitializer
3 يمكنك أيضًا استخدام تعليق توضيحي HandLestypes لتحميل الفئة المحددة عند بدء التطبيق.
عملية ومبادئ tomcat الخارجية
① ابدأ Tomcat
② وفقًا لقواعد Servlet3.0+ الموضحة أعلاه ، يمكنك العثور على ملف يدعى javax.servlet.servletcontainerinitializer في وحدة الويب Spring Web ، ومحتوى الملف هو org.springframework.web.springservletcontainerinitializer ، الذي يستخدم لتحميل SpringservletInerIlizer.
③ في تعريف SpringservletContainerInitializer
HandLestypes (webapplicationInitializer.class) الفئة العامة SpringServletContainerInitializer تنفذ servletContainerInitializer { /** * تفويض تطبيق {code servletcontext} إلى أي {link webapplicationInitializer} * الموجود على classpath التطبيق. * <p> لأن هذه الفئة تعلن@{@code handlestypes (webapplicationInitializer.class)} ، ستقوم حاويات Servlet 3.0+ بمسح ClassPath تلقائيًا للتطبيقات * من {code webapplicinitializer} وتوفير مجموعة من جميع هذه الأنواع إلى {@code webappinitializerclass}. * <p> إذا لم يتم العثور على تطبيقات webapplicationInitializer} على classpath ، * هذه الطريقة هي بشكل فعال عدم وجود op. سيتم إصدار رسالة سجل على مستوى المعلومات لإخطار المستخدم بأنه تم استدعاء {code servletContainerInitializer} ولكن تم العثور على تطبيقات webapplicationInitializer}. * <p> على افتراض أنه تم اكتشاف أنواع واحدة أو أكثر {code webapplicationInitializer} ، * سيتم إنشاء مثيل لها (و <em> فرز </em> إذا كان@@inin تم تنفيذها. مكونات مثل المرشحات. onStartup (set <؟ >> webappinitializerclasses ، servletcontext servletcontex) الدفاع: بعض حاويات servlet تزودنا بفئات غير صالحة ، // بغض النظر عن ما يقوله Handlestypes ... إذا (! waiclass.isinterface () &&! modifier.isabstract (waiclass.getModifiers ()) initializers. classpath ") ؛ return ؛} servletcontext.log (initializers.size () +" Spring WebApplicationInitializers المكتشفة على classpath ") ؛ enoTationAwareDordomparator.sort (initializers) ؛ // استدعاء طريقة onStartup لكل webapplicationInitializer for (webapplicationInitializer: enthitter) }}}في التعليق الطويل أعلاه ، يمكنك أن ترى أن SpringServletContainerInitializer يمرر جميع فئات نوع WebApplicationInitializer المشروع بواسطة Handlestypes (WebapplicationInitializer.class) في المعلمة المحددة لطريقة OnStartup ، وإنشاء حالات لأنواع الخلاصية هذه عن طريق الانعكاس ؛
④ الطريقة في النهاية ، يستدعي كل تطبيق webapplicationInitilizer طريقة OnStartup الخاصة به
webapplicationInitializer لديه فئة مجردة تنفيذ springbootservletinitializer (تذكر أننا ورثنا هذه الفئة التجريدية) ، وسيتم تسمية طريقة onStartup لكل مثيل webapplicationInitializer (بما في ذلك springbootservletinitializer):
Public Class SpringBootServleTinitializer تنفذ webapplicationInitializer {// رمز آخر ... Override public void onStartup (servletContext servletContext) يلقي servletexception {// logger تهيئة في حالة A // logsservletcontinitializizializer هذا. // إنشاء IOC Container WebApplicationContext ROOTAPPCONTEXT = CREATEROOTAPPLICATIONCONTEXT (servletContext) ؛ if (rootAppContext! = null) {servletContext.addListener (contextLoaderListener جديد (ROOTAPPContext) {Override public void contextInitialized (servletContexTevent Event) {// no-op لأن سياق التطبيق قد تم تهيئته بالفعل}}) ؛ } آخر {this.logger.debug ("لا يوجد contextloaderListener مسجل ، مثل" + "createrootapplicationContext () لم" + "إرجاع سياق التطبيق") ؛ }} محمية webapplicationContext createrootapplicationContext (servletContext servletContext) {// إنشاء منشئ تطبيق الربيع وقم بتعيين الخصائص ذات الصلة springapplicationbuilder builder = createSpringApplicationBuilder () ؛ بيئة المعايير servletenvionment = المعايير الجديدة servletenvironment () ؛ البيئة. builder.environment (البيئة) ؛ builder.main (getClass ()) ؛ ApplicationContext parent = getExistingRootWebApplicationContext (servletContext) ؛ if (parent! = null) {this.logger.info ("سياق الجذر الذي تم إنشاؤه بالفعل (باستخدام الوالد).") ؛ servletContext.setAttribute (WebapPlicationContext.root_web_application_context_attribute ، null) ؛ Builder.Initializers (New ParentContextApplicationContextInitializer (Parent)) ؛ } builder.initializers (servletcontextapplicationContInitializer (servletContext)) ؛ builder.contextClass (enrotationConfigemBedDedWebapplicationContext.class) ؛ // بعد استدعاء طريقة التكوين وإنشاء مشروع ويب من نوع الحرب ، نظرًا لأن الفئة الفرعية لـ SpringBootServleTinitializer تتجاوز طريقة التكوين ، فإن طريقة التكوين التي حددناها تُعرف هنا. Builder = تكوين (منشئ) ؛ // تم تصميم تطبيق Spring من خلال تطبيق Builder SpringApplication = builder.build () ؛ if (application.getSources (). isEmpty () && enrotationUtils .FindAnnotation (getClass () ، configuration.class)! = null) {application.getSources (). add (getClass ()) ؛ } assert.state (! application.getsources (). isempty () ، "لم يتم تعريف مصادر springapplication. إما تجاوز طريقة تكوين" + "أو إضافة توضيح التكوين") ؛ // تأكد من تسجيل صفحات الخطأ إذا (this.registerErrorpageFilter) {application.getSources (). Add (ErrorPageFilterConfiguration.class) ؛ } // ابدأ تشغيل تطبيق الربيع return Run (Application) ؛ } // يبدأ تطبيق الربيع ، ويقوم بإنشاء وإرجاع حاوية IOC المحمية WebApplicationContext Run (تطبيق SpringApplication) {return (WebapPlicationContext) Application.run () ؛ }}عندما ينفذ مثيل springBootServleTinitializer طريقة OnStartUp ، سيتم تنفيذ طريقة التشغيل من خلال طريقة creachapplicationContext. العملية التالية هي نفس عملية تشغيل التطبيق التي بدأت في شكل حزمة جرة. سيتم إنشاء حاوية IOC داخليًا وإعادتها. ومع ذلك ، فإن التطبيق في شكل حزمة الحرب لن ينشئ حاوية Servlet أثناء عملية إنشاء حاوية IOC.
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.