Baru -baru ini, saya punya waktu untuk mengoptimalkan platform API terbuka perusahaan. Ketika saya mengetik paket JAR, tiba -tiba saya menyadari bahwa saya sangat terampil dalam menggunakan boot musim semi sebelumnya, tetapi saya tidak pernah tahu prinsip awal toples yang diproduksi oleh Spring Boot. Lalu aku membuka ritsleting toples kali ini dan melihatnya. Itu sangat berbeda dari apa yang saya bayangkan. Berikut ini adalah analisis lengkap dari toples yang belum di -zip.
Aplikasi Spring Boot tidak diposting. Struktur demo yang lebih sederhana serupa. Selain itu, versi boot musim semi yang saya gunakan adalah 1.4.1. Ada artikel lain di internet untuk menganalisis startup toples boot musim semi. Itu harus di bawah 1.4, dan metode startup juga sangat berbeda dari versi saat ini.
Setelah pemasangan MVN Clean, ketika kami melihat di direktori target, kami akan menemukan dua paket stoples, sebagai berikut:
xxxx.jarxxx.jar.original
Ini dikaitkan dengan mekanisme plug-in boot pegas, yang mengubah toples biasa menjadi paket toples yang dapat dieksekusi, dan xxx.jar.original adalah paket jar yang diproduksi oleh Maven. Ini dapat ditemukan mengacu pada artikel di situs web Spring resmi, sebagai berikut:
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar
Berikut ini adalah bagian dari struktur direktori toples yang diproduksi oleh aplikasi boot pegas, yang sebagian besar dihilangkan, dan hanya bagian -bagian penting yang ditampilkan.
.├── BOOT-INF│ ├── classes│ ├── application-dev.properties│ │ ├── application-prod.properties│ │ ├── application.properties│ │ │ │ └── com│ │ │ │ └── weibangong│ │ │ └── open│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └ ─ ─ │ │ │ │ │ │ └ └ ─ ─ ─ uman ─ ─ ─ ─ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ │ │ │ │ │ └── Swaggerconfig.class│ │ │ │ │ ├ ─ ─ oAuth2│ │ │ ├ ├ uas ├ ├ ├ ├ ├ ├ ├ ├ ├ └ ├ ├ ├ ├ ├ │ │ └ └ └ ├ ├ ├ ├ ├ │ └ └ ├ ├ ├ ├ │ ├ ├ ├ ├ ├ ├ ├ ├ │ ├ │ ├ ├ ├ ├ ├ ├ ├ ├ ├ ├ │ ├ ├ ├ ├ ├ ├ │ └ ├ ├ ├ ├ ├ │ │ └ │ ├ └ └ ├ ├ ├ ├ Guru.css│ │ ├── ─ │ ├ ─ urasan fbcover1200x628.png│ │ └── ─ ─ ─ ─ ─ ilangan ─ ─ ─ ilangan ─ ilangan ilangan moTa └ ─ └── open-server-openapi│ ├── pom.properties│ └── pom.xml└── org └── Springframework └── └ uman loader ├ ├ olaket ├ ilangan ilangan loader ├ ├ olaket ├ uman ├ olaket ├ olaket ├ ─ ├── LaunchedURLClassLoader.class ├── Launcher.class ├── archive │ ├── Archive$Entry.class │ ├── Archive$EntryFilter.class │ ├── Archive.class │ ├── ExplodedArchive$1.class │ ├── ExplodedArchive$FileEntry.class │ ├── ExplodedArchive $ FileEntryIterator $ entryComparator.class ├── explodedArchive $ FileEntryIterator.class
Selain kelas yang kami tulis di aplikasi, toples ini juga memiliki paket org terpisah. Seharusnya aplikasi Spring Boot menggunakan plugin Spring Boot untuk memasukkan paket ini, yaitu untuk meningkatkan tahap paket dalam siklus hidup MVN. Paket inilah yang memainkan peran kunci dalam proses startup. Selain itu, berbagai dependensi yang diperlukan oleh aplikasi dimasukkan dalam toples dan paket tambahan boot musim semi dimasukkan. Jar ini yang bisa semua-dalam-satu juga disebut Fat.jar. Di sini kita akan selalu menggunakan Fat.jar untuk mengganti nama toples.
Pada saat ini, kami akan terus melihat file manifest.mf di meta-inf, sebagai berikut:
Manifest-Versi: 1.0Implementation-title: Open :: Server :: OpenApiImplement-Versi: 1.0-Snapshotarchiver-Version: plexus archiverbuilt-by: xiaxuanImlementation-vendor-id: com.weabangong.openspring-boot-versi: 1.4.14. Inc.Main-Class: org.springframework.boot.loader.propertieslauncherstart-class: com.weibangong.open.openapi.springbootwapplicationspring-boot-class: boot-inf/class/spring-boot-lib: boot-inf/lib/created-for 1.8.0_20Implementation-url: http://maven.apache.org/open-server-openapi
Kelas utama yang ditentukan di sini adalah file kelas dalam paket yang dimasukkan secara terpisah alih-alih program startup kami, dan kemudian file manifest.mf memiliki kelas awal terpisah yang menentukan program startup aplikasi kami.
Pertama kami menemukan kelas org.springframework.boot.loader.propertieslauncher, di mana metode utamanya adalah:
public static void main (string [] args) melempar Exception {propertiesLauncher peluncur = new PropertiesLauncher (); args = peluncur.getArgs (args); Launcher.launch (args);}Periksa metode peluncuran. Metode ini ditemukan di peluncur kelas induk dan metode peluncuran kelas induk adalah sebagai berikut:
peluncuran void yang dilindungi (String [] args, String MainClass, ClassLoader ClassLoader) melempar Exception {thread.currentThread (). SetContextClassLoader (ClassLoader); this.createMainMethodrunner (MainClass, Args, ClassLoader) .run (); } protected MainMethodrunner CreateMainMethodRunner (String MainClass, String [] args, ClassLoader ClassLoader) {return baru MainMethodRunner (MainClass, args); }Metode peluncuran akhirnya memanggil metode CreateMainMethodrunner, yang membuat objek MainMethodrunner dan menjalankan metode RUN. Kami pergi ke kode sumber MainMethodrunner, sebagai berikut:
Paket org.springframework.boot.loader; import java.lang.reflect.method; kelas publik Mainmethodrunner {private final string mainClassName; string final pribadi [] args; publik MainMethodRunner (String MainClass, String [] args) {this.mainclassName = MainClass; this.args = args == null? null: (string []) args.clone (); } public void run () melempar Exception {class mainClass = thread.currentThread (). getContextClassLoader (). LoadClass (this.mainclassName); Metode MainMethod = MainClass.GetDecLaredMethod ("Main", kelas baru [] {string []. Class}); mainMethod.invoke ((objek) null, objek baru [] {this.args}); }}Memeriksa metode run, sangat mudah untuk menjalankan stoples boot musim semi, dan analisisnya pada dasarnya berakhir.
5. Proses startup program utama
Setelah berbicara tentang proses awal JAR, mari kita bicara tentang proses startup dan pemuatan program utama dalam aplikasi Spring Boot. Pertama, mari kita lihat metode utama aplikasi boot Spring.
Paket cn.com.devh; impor org.springframework.boot.springapplication; impor org.springframework.boot.autoconfigure.springbootApplication; impor org.springframework.cloud.client.discovery.enableDiscovery -clientycovery; org.springframework.cloud.netflix.eureka.enableeureKaclient; impor org.springframework.cloud.netflix.feign.enablefeignclients;/*** dibuat oleh Xiaxuan pada 17/8/25. */@SpringbootApplication@enablefeignclients@enableeureKaclientPublic kelas A1ServiceApplication {public static void main (string [] args) {springApplication.run (a1ServiceApplication.class, args); }}Pergi ke Metode Jalankan di SpringApplication, sebagai berikut:
/** * helper statis yang dapat digunakan untuk menjalankan {@link springApplication} dari * sumber yang ditentukan menggunakan pengaturan default. * @param Sumber Sumber untuk memuat * @param args argumen aplikasi (biasanya diturunkan dari metode utama java) * @return runing {@link applicationContext} */ public static configurableApplicationContext run (sumber objek, string ... args) {return run (objek baru [] {sumber}, args); } /** * helper statis yang dapat digunakan untuk menjalankan {@link springApplication} dari * sumber yang ditentukan menggunakan pengaturan default dan argumen yang disediakan pengguna. * @param Sumber Sumber untuk memuat * @param args argumen aplikasi (biasanya ditularkan dari metode utama Java) * @return The running {@link applicationContext} */ public static configurableApplicationContext run (Sumber Object [], string [] args) {return New SpringApplication (sumber). }Di sini instantiasi springapplication adalah kuncinya, kita pergi ke springapplikasi konstruktor.
/*** Buat instance {@link springApplication} baru. Konteks aplikasi akan memuat * kacang dari sumber yang ditentukan (lihat {@link springApplication kelas kelas} * dokumentasi untuk perincian. Contohnya dapat disesuaikan sebelum memanggil * {@link #run (string ...)}. * @Param Sumber (Sumber Publing (Objek, Objek, String []) * @See #See #SEPEPPLINGCECED * @See #Run (Object, String []) * @See #See #SEPEPLINGCECECECECECECECECECED, OBSID (OBDACE, STRING []) * @See #SEE #SEE #sEpping {inisialisasi (sumber); ApplicationContextInitializer.class));DeduceWebenvironment () Dalam metode inisialisasi di sini menentukan apakah saat ini dimulai dengan aplikasi web atau toples normal, sebagai berikut:
private boolean deduceWebEnvironment () {for (string className: web_environment_classses) {if (! classutils.ispresent (classname, null)) {return false; }} return true; }Web_environment_classes adalah:
Private Static Final String [] Web_environment_Classes = {"javax.servlet.servlet", "org.springframework.web.context.configableableWebApplicationContext"};Selama salah satu dari mereka tidak ada, aplikasi saat ini dimulai dalam bentuk toples normal.
Kemudian metode SetInitializers menginisialisasi semua ApplicationContextInitializer,
/** * Mengatur {@link applicationContextInitializer} yang akan diterapkan pada pegas * {@link applicationContext}. * @param inisialisasi inisialisasi untuk mengatur */ public void setInitializers (collection <? Extends ApplicationContextInitializer <? >> Inisialisasi) {this.initializers = ArrayList baru <ApplicationContextInitializer <? >> (); this.initializers.addall (inisialisasi); } setListeners ((koleksi) getspringfactoriesinstances (applicationListener.class)) **Langkah ini menginisialisasi semua pendengar.
Mari kita kembali ke springapplication (sumber) sebelumnya .run (args); dan masukkan metode run, kodenya adalah sebagai berikut:
/** * Jalankan aplikasi Spring, buat dan menyegarkan * {@link applicationContext} yang baru. * @param Args Argumen Aplikasi (biasanya diteruskan dari metode utama Java) * @return a running {@link applicationContext} */ public configurableApplicationContext run (string ... args) {stopwatch stopwatch = stopwatch baru (); stopwatch.start (); ConfigurableApplicationContext Context = NULL; configureheadlessProperty (); SpringApplicationRunListeners listeners = getRunListeners (args); pendengar.Started (); coba {applicationArguments applicationArguments = new DefaultApplicationArguments (args); Context = CreateAndrefreshContext (pendengar, ApplicationArguments); Afterrefresh (konteks, aplikasi aplikasi); pendengar.Finished (konteks, null); stopwatch.stop (); if (this.logstartupInfo) {startupInfologger baru (this.mainApplicationClass) .logStarted (getApplicationLog (), stopwatch); } kembali konteks; } catch (Throwable ex) {handlerunfailure (konteks, pendengar, ex); Lempar IlegalStateException baru (EX); }}Langkah ini melakukan pembuatan konteks CreateandrefreshContext (pendengar, ApplicationArguments),
Private ConfigurableApplicationContext CreateAndDrefreshContext (SpringApplicationRunListeners Listeners, ApplicationArguments ApplicationArguments) {ConfigurableApplicationContext Context; // Buat dan konfigurasikan lingkungan yang dapat dikonfigurasi lingkungan lingkungan = getorcreateeNvironment (); configureenvironment (lingkungan, applicationArguments.getSourCeARGS ()); pendengar. if (isWebEnvironment (lingkungan) &&! this.webenvironment) {lingkungan = convertToStOdardenvironment (lingkungan); } if (this.banNermode! = Banner.mode.off) {printbanner (lingkungan); } // Buat, memuat, menyegarkan, dan menjalankan ApplicationContext Context = CreateApplicationContext (); Context.Setenvironment (Lingkungan); PostProcessApplicationContext (konteks); ApplyInitializers (konteks); listeners.contextprepared (konteks); if (this.logstartupInfo) {logstartupInfo (context.getParent () == null); logstartupprofileInfo (konteks); } // Tambahkan boot spesifik Singleton Beans Context.getBeanFactory (). Registersingleton ("SpringApplicationArguments", ApplicationArguments); // Muat Sumber Set <PERBICARA> SUMBER = GetSources (); Assert.notempty (sumber, "sumber tidak boleh kosong"); muat (konteks, sumber.toArray (objek baru [sumber.size ()])); listeners.contextLoaded (konteks); // Segarkan refresh konteks (konteks); if (this.registershutdownHook) {coba {context.registershutdownHook (); } catch (accessControlException ex) {// Tidak diizinkan di beberapa lingkungan. }} return Context; } // Buat dan konfigurasikan lingkungan yang dapat dikonfigurasi lingkungan lingkungan = getorcreateeNvironment (); configureenvironment (lingkungan, applicationArguments.getSourCeARGS ());Langkah ini melaksanakan konfigurasi dan pemuatan lingkungan.
if (this.bannermode! = Banner.mode.off) {printbanner (lingkungan); }Langkah ini mencetak logo Spring Boot. Jika Anda perlu mengubahnya, tambahkan Banner.txt dan Banner.txt ke file sumber daya untuk mengubahnya ke pola yang Anda butuhkan.
// Buat, memuat, menyegarkan, dan menjalankan ApplicationContext Context = CreateApplicationContext (); return (ConfigurableApplicationContext) beanutils.instantiate (ContextClass)
Konteks penciptaan benar -benar mencakup wadah apa yang dibuat dan membuat kelas respons, termasuk penciptaan embeddedServletContainererFactory, apakah akan memilih Jetty atau Tomcat, ada banyak konten, jadi saya akan membicarakannya lain kali.
if (this.registershutdownHook) {coba {context.registershutdownHook (); } catch (accessControlException ex) {// Tidak diizinkan di beberapa lingkungan. }}Langkah ini adalah mendaftarkan konteks saat ini, dan menghancurkan wadah ketika perintah membunuh diterima.
Pada dasarnya, analisis start-up sudah berakhir, tetapi masih ada beberapa detail yang sangat memakan waktu untuk diceritakan. Ini akan dibahas dalam posting blog berikutnya, dan itu saja untuk hari ini.
Singkatnya, proses startup toples boot musim semi pada dasarnya adalah langkah -langkah berikut:
1. Ketika kami mengemas Maven secara normal, plug-in boot pegas memperluas siklus hidup Maven dan memberikan paket terkait boot musim semi ke dalam toples. Guci ini berisi file kelas yang terkait dengan program startup Spring Boot selain stoples yang diproduksi oleh aplikasi.
2. Saya telah melihat proses startup dari stoples boot spring yang sedikit lebih rendah sebelumnya. Pada saat itu, saya ingat bahwa utas saat ini memiliki utas baru untuk menjalankan program utama, dan sekarang telah diubah untuk secara langsung menggunakan refleksi untuk memulai program utama.
Meringkaskan
Di atas adalah analisis prinsip toples boot musim semi yang diperkenalkan kepada Anda oleh editor. Saya harap ini akan membantu Anda. Jika Anda memiliki pertanyaan, silakan tinggalkan saya pesan dan editor akan membalas Anda tepat waktu. Terima kasih banyak atas dukungan Anda ke situs web Wulin.com!