في الآونة الأخيرة ، لدي وقت لتحسين منصة API المفتوحة للشركة. عندما كنت أكتب حزمة الجرة ، أدركت فجأة أنني كنت ماهرًا للغاية في استخدام Spring Boot من قبل ، لكنني لم أعرف أبدًا مبدأ البداية للجرة التي تنتجها SPRING BOOT. ثم قمت بفك الجرة هذه المرة ونظرت إليها. كان مختلفًا حقًا عما تخيلته. فيما يلي تحليل كامل للجرة غير المصغرة.
لم يتم نشر تطبيق SPRING BOOT. هيكل العرض التوضيحي أبسط مماثل. بالإضافة إلى ذلك ، فإن إصدار Spring Boot الذي استخدمته هو 1.4.1. هناك مقال آخر على الإنترنت لتحليل بدء تشغيل جرة SPRING BOOT. يجب أن يكون هذا أقل من 1.4 ، وتختلف طريقة بدء التشغيل أيضًا عن الإصدار الحالي.
بعد تثبيت MVN Clean ، عندما ننظر إلى الدليل المستهدف ، سنجد حزمتين جرة ، على النحو التالي:
xxxx.jarxxx.jar.original
ويعزى ذلك إلى آلية Spring Boot Plug-In ، التي تحول جرة عادية إلى حزمة جرة قابلة للتنفيذ ، و xxx.jar.original هي حزمة جرة تنتجها Maven. يمكن العثور عليها في إشارة إلى المقالة على موقع الربيع الرسمي ، على النحو التالي:
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar
ما يلي جزء من بنية الدليل للجرة التي ينتجها تطبيق Boot SPRING ، والتي يتم حذف معظمها ، ويتم عرض الأجزاء المهمة فقط.
.-inf ├ ├ classes ├ application application-dev.properties│ │ ├ Application-prod.properties│ │ ├ application application application application │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └ └ │ │ │ │ └ └ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └ └ └ └ │ │ │ │ │ └ └ └ └ └ │ │ │ │ │ │ └ swaggerConfig.class│ │ │ │ ├ ├ ├ oauth2│ │ │ ├ ├ ├ ├ └ guru.css│ │ ├ ├ ├ │ │ │ fbcover1200x628.png│ │ └ newbannerboots_2.png│ com.weibangong.Open│ └ Open-Openapi│ ├ pom.properties│ └ pom.xml└ org └ springframewwork LaunchedUrlClassloader $ 1.class ├ LaunchedUrlClassloader.class ├ Launcher.class ├ الأرشيف │ ├ ├ Archive $ Entry.class │ │ ├ $ $ $ $ entry │ │ │ │ │ │ ├ │ │ ├ │ ├ ├ │ │ │ │ │ ├ ├ ├ ├ ├ ├ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │. ├ OperDedarchive $ fileEntryIterator $ intplassomparator.class ├ OperDedArchive $ fileEntryIterator.class
بالإضافة إلى الفصل الذي كتبناه في التطبيق ، تحتوي هذه الجرة أيضًا على حزمة ORG منفصلة. يجب أن يستخدم تطبيق SPRING Boot Plugin Spring Boot للدخول إلى هذه الحزمة ، وهو تحسين مرحلة الحزمة في دورة حياة MVN. هذه الحزمة التي تلعب دورًا رئيسيًا في عملية بدء التشغيل. بالإضافة إلى ذلك ، يتم إدخال التبعيات المختلفة التي يتطلبها التطبيق في الجرة ويتم إدخال الحزمة الإضافية من Boot Spring. هذه الجرة التي يمكن أن تسمى الكل في واحد أيضا fat.jar. هنا سوف نستخدم دائمًا fat.jar لاستبدال اسم الجرة.
في هذا الوقت ، سوف نستمر في النظر إلى ملف manisest.mf في meta-inf ، على النحو التالي:
بيان واضح: 1.0Implementation-title: Open :: Server :: OpenApiMplement-version: 1.0-snapshotarchiver-version: Plexus Archiverbuilt-by: org.springframework.boot.loader.propertiesLauncherStart-class: com.weibangong.open.openapi.springbootwotwabplicationspring-boot-classes: boot-inf/classes/spring-boot-lib: boot-inf/lip-by: apache maven 3.3.9build-jdk 1.8.0_20Implementation-url: http://maven.apache.org/open-server-openapi
الفئة الرئيسية المحددة هنا هو ملف فئة في الحزمة التي يتم إدخالها بشكل منفصل بدلاً من برنامج بدء التشغيل الخاص بنا ، ثم يحتوي ملف MISSEST.MF على فئة بدء منفصلة تحدد برنامج بدء التشغيل في تطبيقنا.
أولاً ، نجد الفصل الدراسي
static static void main (string [] args) يلقي الاستثناء {propertiesLauncher Launcher = new propertiesLauncher () ؛ args = launcher.getargs (args) ؛ Launcher.Launch (args) ؛}تحقق من طريقة الإطلاق. تم العثور على هذه الطريقة في قاذفة الفئة الأصل وطريقة إطلاق الفئة الأصل على النحو التالي:
إطلاق الفراغ المحمي (string [] args ، سلسلة mainclass ، classloader classloader) يلقي استثناء {thread.currentThread (). this.createmainmethodrunner (mainclass ، args ، classloader) .run () ؛ } MainMethodRunner المحمي CreateMainMethodRunner (سلسلة mainclass ، سلسلة [] args ، classloader classloader) {return mainmethodrunner جديد (mainclass ، args) ؛ }تدعو طريقة الإطلاق أخيرًا طريقة CreateMainMethodRunner ، والتي تقوم بتثبيت كائن MainMethodRunner وتشغيل طريقة التشغيل. نذهب إلى رمز مصدر MainMethodrunner ، على النحو التالي:
package org.springframework.boot.loader ؛ import java.lang.reflect.method ؛ public class mainmethodrunner {private Final String MainClassName ؛ سلسلة نهائية خاصة [] args ؛ MainMethodRunner العامة (سلسلة mainclass ، سلسلة [] args) {this.mainClassName = mainclass ؛ this.args = args == null؟ null: (string []) args.clone () ؛ } public void run () rems {class mainclass = thread.currentThread (). الطريقة mainMethod = mainclass.getDeclaredMethod ("main" ، فئة جديدة [] {string []. class}) ؛ MainMethod.invoke ((Object) null ، كائن جديد [] {this.args}) ؛ }}التحقق من طريقة التشغيل ، من السهل جدًا تشغيل جرة التمهيد الربيعي ، والتحليل قد انتهى بشكل أساسي.
5. عملية بدء التشغيل للبرنامج الرئيسي
بعد الحديث عن عملية البدء في جرة ، دعنا نتحدث عن عملية بدء التشغيل والتحميل للبرنامج الرئيسي في تطبيق Boot Spring. أولاً ، دعونا نلقي نظرة على الطريقة الرئيسية لتطبيق Boot Spring.
package cn.com.devh ؛ استيراد org.springframework.boot.springapplication ؛ استيراد org.springframework.boot.autoconfigure.springbootapplication ؛ import org.springframework.cloud.client.discovery.enabilitisclient ؛ org.springframework.cloud.netflix.eureka.enableeurekaclient ؛ استيراد org.springframework.cloud.netflix.feign.enablefeignclients ؛/*** تم إنشاؤه بواسطة Xiaxuan في 17/8/25. */@springbootapplication@enablefeignclients@enableeurekaclientpublic class a1serviceapplication {public static void main (string [] args) {springapplication.run (a1serviceapplication.class ، args) ؛ }}انتقل إلى طريقة التشغيل في Springapplication ، على النحو التالي:
/** * مساعد ثابت يمكن استخدامه لتشغيل {link springapplication} من المصدر المحدد باستخدام الإعدادات الافتراضية. * param source المصدر لتحميل * param args وسيطات التطبيق (عادة ما يتم تمريرها من طريقة java الرئيسية) * return تشغيل {link applicationContext} */ public static configurableApplicationContext Run (مصدر الكائن ، السلسلة ... args) {return run (كائن جديد {source} ، args) ؛ } /** * المساعد الثابت الذي يمكن استخدامه لتشغيل {link springapplication} من المصادر المحددة باستخدام الإعدادات الافتراضية والوسائط المقدمة من المستخدم. * param مصادر المصادر لتحميل * param args وسيطات التطبيق (عادة ما يتم تمريرها من طريقة java الرئيسية) * return تشغيل {link applicationContext} */ public static configurableApplicationContext Run (Object [] sources ، string [] }هنا ، هو المفتاح ، نذهب إلى مُنشئ Springapplication.
/*** إنشاء مثيل {link springapplication} جديد. سيقوم سياق التطبيق بتحميل * الفاصوليا من المصادر المحددة (انظر {link springapplication على مستوى الفئة} * * الوثائق للحصول على التفاصيل. يمكن تخصيص المثيل قبل الاتصال * {link #run (سلسلة ...)}. المصادر) {تهيئة (مصادر) ؛ ApplicationContextInitializer) ؛يحدد PromuceWebenVironment () في طريقة التهيئة هنا ما إذا كان قد تم تشغيله حاليًا بتطبيق ويب أو جرة عادية ، على النحو التالي:
private boolean QualueWebenVironment () {for (string className: web_environment_classes) {if (! classUtils.ispresent (className ، null)) {return false ؛ }} إرجاع صحيح ؛ }Web_environment_classes هي:
السلسلة النهائية الثابتة الخاصة [] web_environment_classes = {"javax.servlet.servlet" ، "org.springframework.web.context.configableWebapplicationContext"} ؛طالما لم يكن أي منهم موجودًا ، يتم بدء التطبيق الحالي في شكل جرة طبيعية.
ثم تقوم طريقة setInitializers بتهيئة جميع ApplicationContextInitializers ،
/** * يعين {link applicationContextInitializer} الذي سيتم تطبيقه على spring * {link ApplicationContext}. * param initializers inializers لتعيين */ public void setInitializers (مجموعة <؟ تمديد ApplicationContextInitializer <؟ >> المهيئات) {this.initializers = new ArrayList <applicationContInitializer <؟ >> () ؛ this.initializers.addall (المهيئات) ؛ } setListeners ((Collection) getSpringFactoriesInstances (ApplicationListener.class)) **هذه الخطوة تهيئة جميع المستمعين.
دعنا نعود إلى springapplication (المصادر) .Run (args) ؛ وأدخل طريقة التشغيل ، الرمز كما يلي:
/** * قم بتشغيل تطبيق الربيع ، وإنشاء وتحديث جديد * {link applicationContext}. * param args وسيطات التطبيق (عادة ما يتم تمريرها من طريقة java الرئيسية) * return تشغيل {link ApplicationContext} */ public configurableApplicationContext Run (string ... args) {sTropwatch stopwatch = new stopwatch () ؛ توقيت. ستارت () ؛ configurableApplicationContext context = null ؛ ConfigureDheadlessProperty () ؛ springapplicationRunlisteners المستمعين = getRunListeners (args) ؛ المستمعين. جرب {ApplicationArguments ApplicationArguments = defaultApplicationArguments (args) ؛ Context = CreateAndRefreshContext (المستمعين ، ApplicationArguments) ؛ Afterrefresh (السياق ، ApplicationArguments) ؛ المستمعين. ساعة توقيت. stop () ؛ if (this.logstartupinfo) {new StartupInfologger (this.mainapplicationClass) .logStarted (getApplicationLog () ، stalpwatch) ؛ سياق الإرجاع ؛ } catch (throwable ex) {handlerunfailure (السياق ، المستمعين ، السابقين) ؛ رمي الجديد غير القانوني stateException (ex) ؛ }}هذه الخطوة تنفذ إنشاء السياق CreateAndRefreshContext (المستمعين ، ApplicationArguments) ،
configurableApplicationContext CreateAndRefreshContext (مستمعين springapplicationRunlisteners ، ApplicationArguments ApplicationArguments) {configurableApplicationContext Context ؛ // إنشاء وتكوين بيئة البيئة القابلة للتكوين = getorcreateenVironment () ؛ configenvironment (البيئة ، ApplicationArguments.GetSourCeargs ()) ؛ المستمعين. if (isWebenVironment (البيئة) &&! هذا. } if (this.bannermode! = banner.mode.off) {printbanner (evely) ؛ } // إنشاء وتحميل وتحديث وتشغيل ApplicationContext Context = createApplicationContext () ؛ سياق. postprocessapplicationContext (السياق) ؛ ApplyInitializers (السياق) ؛ المستمعين. contextpreped (السياق) ؛ if (this.logstartupinfo) {logStartupInfo (context.getParent () == null) ؛ logstartupprofileInfo (السياق) ؛ }. // تحميل مجموعة المصادر <Object> المصادر = getSources () ؛ تأكيد. notempty (المصادر ، "يجب ألا تكون المصادر فارغة") ؛ load (Context ، Sources.ToArray (comple new [sources.size ()])) ؛ المستمعين. contextloaded (السياق) ؛ // تحديث تحديث السياق (السياق) ؛ if (this.registerShutDownHook) {try {context.registerShutDownHook () ؛ } catch (AccessControlexception ex) {// غير مسموح به في بعض البيئات. }} سياق الإرجاع ؛ } // إنشاء وتكوين بيئة البيئة القابلة للتكوين = getorcreateenVironment () ؛ configenvironment (البيئة ، ApplicationArguments.GetSourCeargs ()) ؛تنفذ هذه الخطوة تكوين البيئة وتحميلها.
if (this.bannermode! = banner.mode.off) {printBanner (evely) ؛ }هذه الخطوة تطبع شعار التمهيد الربيع. إذا كنت بحاجة إلى تغييره ، فأضف banner.txt و banner.txt إلى ملف المورد لتغييره إلى النمط الذي تحتاجه.
// إنشاء ، تحميل ، تحديث وتشغيل ApplicationContext Context = createApplicationContext () ؛ إرجاع (configurableApplicationContext) BeanUtils.instantiate (ContextClass)
يتضمن سياق الإنشاء حقًا ما الذي يتم إنشاؤه الحاوية وتثبيت فئة الاستجابة ، بما في ذلك إنشاء intibedServletContainerFactory ، سواء للاختيار رصيفًا أو tomcat ، هناك الكثير من المحتوى ، لذلك سأتحدث عنه في المرة القادمة.
if (this.registerShutDownHook) {try {context.registerShutDownHook () ؛ } catch (AccessControlexception ex) {// غير مسموح به في بعض البيئات. }}هذه الخطوة هي تسجيل السياق الحالي ، وتدمير الحاوية عند استلام أمر القتل.
في الأساس ، انتهى تحليل بدء التشغيل ، ولكن لا يزال هناك بعض التفاصيل التي تستغرق وقتًا طويلاً في تحديدها. سيتم مناقشة هذا في منشور المدونة اللاحق ، وهذا كل شيء لهذا اليوم.
باختصار ، فإن عملية بدء تشغيل جرة SPRING SPRING هي الخطوات التالية:
1. عندما نقوم بتعبئة Maven بشكل طبيعي ، يقوم مكون Spring Boot بتوسيع دورة حياة Maven وينقل الحزمة ذات الصلة بحذاء Spring Boot في الجرة. تحتوي هذه الجرة على ملفات فئة متعلقة ببرنامج بدء تشغيل SPRING BOOT إلى جانب الجرار التي تنتجها التطبيق.
2. لقد رأيت عملية بدء التشغيل لإصدار أقل قليلاً من جرة SPRING BOOT من قبل. في ذلك الوقت ، أتذكر أن الخيط الحالي يحتوي على مؤشر ترابط جديد لتشغيل البرنامج الرئيسي ، والآن تم تغييره لاستخدام الانعكاس المباشر لبدء البرنامج الرئيسي.
لخص
ما سبق هو تحليل مبدأ جرة الحذاء الربيعي الذي قدمه لك المحرر. آمل أن يكون ذلك مفيدًا لك. إذا كان لديك أي أسئلة ، فيرجى ترك رسالة لي وسوف يرد المحرر إليك في الوقت المناسب. شكرا جزيلا لدعمكم لموقع wulin.com!