Kata pengantar
Artikel ini terutama memperkenalkan konten yang relevan tentang proses startup servlet dan prinsip -prinsip dalam boot musim semi. Saya tidak akan mengatakan banyak hal di bawah ini, mari kita lihat perkenalan terperinci bersama.
Proses dan prinsip startup:
1 metode run startup aplikasi boot musim semi
Stopwatch stopwatch = stopwatch baru (); stopwatch.start (); ConfigurableApplicationContext Context = NULL; Analisis FailureAnalyzers = NULL; configureheadlessProperty (); SpringApplicationRunListeners listeners = getRunListeners (args); pendengar.Startting (); coba {applicationArguments applicationArguments = new DefaultApplicationArguments (args); Lingkungan ConfigAbleNeNvironment = Persiapan Lingkungan (Pendengar, ApplicationArguments); Banner PrintedBanner = Printbanner (Lingkungan); // Buat ApplicationContext Container Context = CreateApplicationContext (); Analisis = FailureAnalyzers baru (konteks); prepareContext (konteks, lingkungan, pendengar, aplikasi aplikasi, printedbanner); // Refresh IOC Container RefreshContext (konteks); 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, analisis, ex); Lempar IlegalStateException baru (EX); }2 CreateApplicationContext (): Buat wadah IOC. Jika itu adalah aplikasi web, buat wadah IOC AnnotationConfigembedDedWebApplication. Jika tidak, buat wadah IOC AnnotationConfigapplication.
Public Static Final String Default_Context_Class = "org.springframework.context." + "Annotation.AnnotationConfigApplicationContext"; /** * Nama kelas konteks aplikasi yang akan digunakan secara default untuk lingkungan Web *. */ Public Static Final String Default_Web_Context_Class = "org.springframework." + "boot.context.embedded.annotationConfigembeddedWebApplicationContext"; Dilindungi ConfigurableApplicationContext CreateApplicationContext () {class <?> ContextClass = this.applicationContextClass; if (contextClass == null) {coba {// Buat kontainer IOC yang berbeda sesuai dengan lingkungan aplikasi ContextClass = class.forname (this.webenvironment? Default_web_context_class: default_context_class); } catch (ClassNotFoundException ex) {Throw new IllegalStateException ("Tidak dapat membuat aplikasi default Default," + "Harap tentukan ApplicationContextClass", ex); }} return (configurableApplicationContext) beanutils.instantiate (ContextClass); }3 RefreshContext (Context) Spring Boot menyegarkan wadah IOC (buat objek wadah, inisialisasi wadah, dan buat setiap komponen wadah)
Private void RefreshContext (ConfigurableApplicationContext Context) {Refresh (Context); if (this.registershutdownHook) {coba {context.registershutdownHook (); } catch (accessControlException ex) {// Tidak diizinkan di beberapa lingkungan. }}}}4 Refresh (konteks); Segarkan wadah IOC yang baru saja Anda buat
Protected Void Refresh (ApplicationContext ApplicationContext) {assert.isInstanceof (AbstractApplicationContext.class, ApplicationContext); ((AbstractApplicationContext) ApplicationContext) .refresh (); }5. Hubungi metode penyegaran kelas induk ()
public void refresh () melempar BeansException, IllegalStateException {objek var1 = this.startupshutDownMonitor; disinkronkan (this.startupshutDownMonitor) {this.preparerefresh (); ConfigurableListableBeanFactory beanfactory = this.obtainFreshBeanFactory (); this.preparebeanFactory (beanfactory); coba {this.postprocessBeanFactory (beanFactory); this.invokeBeanFactoryPostProcessors (beanFactory); this.registerbeanPostProcessors (beanFactory); this.initmessageSource (); this.InitApplicationEventMulticaster (); this.onrefresh (); this.registerListeners (); this.finishbeanfactoryInitialisasi (beanfactory); this.finishrefresh (); } catch (beansException var9) {if (this.logger.iswarnEnabled ()) {this.logger.warn ("Pengecualian yang ditemui selama inisialisasi konteks - membatalkan upaya refresh:" + var9); } this.destroybeans (); this.cancelrefresh (var9); lempar var9; } akhirnya {this.resetCommonCaches (); }}}6 Metode Onrefresh dari subclass embeddedWebApplicationContext dari kelas induk abstrak AbstractApplicationContext
@Override Protected void onRefresh () {super.onrefresh (); Coba {createembeddedServletContainer (); } catch (Throwable ex) {Throw ApplicationContextException baru ("Tidak dapat memulai wadah tertanam", ex); }}7 Di createembedservletcontainer, pabrik kontainer servlet tertanam akan diperoleh, dan servlet dibuat dari pabrik kontainer
private void createembeddedServletContainer () {embeddedServletContainer localcontainer = this.embeddedServletContainer; ServletContext localServletContext = getserVletContext (); if (localcontainer == null && localservletcontext == null) {// dapatkan embedded servlet container factory embeddedServletContainerFactory containerFactory = getembedservercontainerFactory (); // Dapatkan wadah servlet tertanam yang sesuai berdasarkan pada pabrik kontainer ini. } lain if (localservletcontext! = null) {coba {getselfInitializer (). onStartup (localservletcontext); } catch (servletException ex) {throw new ApplicationContextException ("Tidak dapat menginisialisasi konteks servlet", ex); }} initpropertysources (); }8 Dapatkan Pabrik Kontainer Servlet dari IOC Container
// embeddedWebApplicationContext#getembeddedservletcontainerfactory dilindungi embeddedServletContainerFactory getembeddedservletcontainerfactory () {// menggunakan nama bean sehingga kami tidak mempertimbangkan string hierarki [] beannames = getBeanFactory () .getBeannamesfortype (embeddedServerContainerFactory.class); if (beannames.length == 0) {throw new ApplicationContextException ("Tidak dapat memulai embeddedWebApplicationContext karena hilang" + "embeddedServletContainerFactory bean."); } if (beannames.length> 1) {throw new ApplicationContextException ("Tidak dapat memulai embeddedWebApplicationContext karena beberapa" + "embeddedServletContainererfactory beans:" + stringutils.arraytocommadelimitedString (beanNames)); } return getBeanFactory (). getbean (beannames [0], embeddedServletContainerFactory.class); }9 Gunakan pabrik wadah servlet untuk mendapatkan wadah servlet tertanam. Pabrik kontainer mana yang akan digunakan tergantung pada ketergantungan lingkungan konfigurasi
this.
10 Proses pembuatan di atas pertama kali memulai wadah IOC, kemudian memulai wadah servlet tertanam, dan kemudian mengambil objek yang tersisa yang tidak dibuat dalam wadah IOC, seperti pengontrol yang Anda buat sendiri.
// Instantiate semua singleton yang tersisa (non-lazy-init). finishbeanfactoryInitialisasi (beanfactory);
void finishbeanFactoryIalization yang dilindungi (configurableListableBeanFactory beanFactory) {// menginisialisasi layanan konversi untuk konteks ini. if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // Daftarkan resolver nilai tertanam default jika tidak ada kacang post-processor // (seperti PropertyplaceHolderConfigurer Bean) terdaftar sebelum: // Pada titik ini, terutama untuk resolusi dalam nilai atribut anotasi. if (! beanfactory.hasembeddedvalueResolver ()) {beanfactory.addembeddedValueResolver (stringValueResolver baru () {@Override Public String ResolVestringValue (string strval) {return getenvironment (). ResolvestringValue (string strval) {return getEnvironment (). ResolVesctringValue (String strval) {return getVironment (). ResolVesveSplace (String strval) {return getEnvironment (). } // Inisialisasi LoadTimeWeAverAware Beans lebih awal untuk memungkinkan mendaftarkan transformer mereka lebih awal. String [] weaverAwareNeSe = beanfactory.getBeanNamesFortype (loadTimeweaverAware.class, false, false); untuk (string weaverawarename: weaverawareNames) {getbean (weaverawareName); } // Berhenti menggunakan classloader sementara untuk pencocokan tipe. beanfactory.settempclassloader (null); // Izinkan caching semua metadata definisi kacang, tidak mengharapkan perubahan lebih lanjut. beanfactory.freezeconfiguration (); // Instantiate semua singleton yang tersisa (non-lazy-init). beanfactory.preinstanticingingingletons (); }Lihatlah metode preinstanticingingletons
public void preINSTANTIATINGINGLETONS () melempar BeansException {if (this.logger.isdebugeNabled ()) {this.logger.debug ("singleton pra-instansiasi di" + this); } Daftar <String> beanNames = ArrayList baru (this.beandefinitionNames); Iterator var2 = beannames.iterator (); while (true) {while (true) {string beanname; Rootbeandefinition bd; do {do {do {if (! var2.hasnext ()) {var2 = beanNames.iterator (); while (var2.hasnext ()) {beanName = (string) var2.next (); Objek singletoninstance = this.getsingleton (beanname); if (singletonInstance instance dari SmartInitializingingSingLeTon) {final SmartInitializingSingLeTon SmartSingleton = (SmartInitializingsingleton) singletoninstance; if (system.getSecurityManager ()! = null) {accessController.dopriviled (new PrivilegedAction <POMPERTIF> () {public Object run () {smartsingleton.AfftersingLeTonSinstantiated (); return null;}, this.getAccessCtrolContext ()); } else {smartsingleton.aftersingletonsInstantiated (); } } kembali; } beanName = (string) var2.next (); bd = this.getmergedlocalbeandefinition (beanname); } while (bd.isabstract ()); } while (! bd.issingleton ()); } while (bd.islazyInit ()); if (this.isfactoryBean (beanName)) {final factorybean <?> factory = (factorybean) this.getBean ("&" + beanname); Boolean ISeAgerInit; if (System.GetSecurityManager ()! = Null && Factory Instance dari SmartFactoryBean) {iSeAgerInit = ((Boolean) AccessController.Doprivileged (baru PrivilegegedAction <Boolean> () {public boolean run () {return ((smartfactorybean) factory). this.getAccessControlContext ())). BooleanValue (); } else {iSeAgerInit = Factory Instance dari SmartFactoryBean && ((SmartFactoryBean) Factory) .IseAgerInit (); } if (iSeAgerInit) {this.getBean (beanName); }} else {// daftarkan bean this.getBean (beanname); }}}}}}}}}}Gunakan metode Getbean untuk membuat semua contoh yang tidak diciptakan melalui refleksi.
Menggunakan wadah servlet tertanam:
Keuntungan: Sederhana, portabel
Kerugian: JSP tidak mendukung secara default, optimisasi dan kustomisasi lebih rumit
Langkah untuk menggunakan wadah servlet eksternal:
1. Proyek perang harus dibuat, dan struktur direktori proyek web Jianhao diperlukan.
2 Lingkup Ketergantungan Tomcat Tertanam Menentukan yang Disediakan
3 Tulis subkelas kelas springbootservletinitializer dan ganti metode konfigurasi
Kelas Publik ServletInitializer memperluas springbootervletInitializer {@Override dilindungi springApplicationBuilder configure (Aplikasi SpringApplicationBuilder) {return application.sources (springboot04webjsplication.class); }}4 Mulai server
Perbedaan antara Paket JAR mulai dan Paket Perang
Paket JAR: Jalankan Metode Jalankan SpringbootApplication, Mulailah Wadah IOC, lalu buat wadah servlet tertanam
Paket Perang: Pertama, Mulai Server Server, Server Memulai Aplikasi Springboot (SpringbootServletInitizer), dan kemudian memulai wadah IOC
Aturan servlet 3.0+
1. Startup Server (Startup Aplikasi Web), akan membuat instance ServletContainerLnitializer di semua paket JAR di aplikasi web saat ini.
2 Implementasi ServletContainerInitializer ditempatkan di folder Meta-Inf/Services dari Paket JAR
3 Anda juga dapat menggunakan anotasi @handlestypes untuk memuat kelas yang ditentukan saat aplikasi dimulai.
Proses dan prinsip tomcat eksternal
① Mulai Tomcat
② Menurut aturan servlet3.0+ yang dijelaskan di atas, Anda dapat menemukan file bernama javax.servlet.servletcontainerInitializer dalam modul web Spring, dan konten file adalah org.springframework.web.springservletcontainerInalizer, yang digunakan untuk memuat springservletcontererererainer.
③ Lihat definisi SpringservletContainerInitializer
@Handlestypes (WebApplicationInitializer.class) kelas publik SpringservletContainerInitializer mengimplementasikan servletContainerInitializer { /** * mendelegasikan {@code servletContext} ke setiap {@link WebAppliclicationInitializer} * implementasi yang ada di classpath {@link. * <p> Karena kelas ini mendeklarasikan@{@@code handleStypes (WebApplicationInitializer.class)}, * Servlet 3.0+ wadah akan secara otomatis memindai classpath untuk implementasi * dari antarmuka spring {@code webapplicationInalizer} ini dan menyediakan serangkaian semua * tipe seperti {@code @code @code @code @code. * <p> Jika tidak ada {@code WebApplicationInitializer} Implementasi ditemukan di classpath, * metode ini secara efektif no-op. Pesan log tingkat info akan dikeluarkan memberi tahu * pengguna bahwa {@code servletContainerInitializer} memang telah dipanggil tetapi bahwa * tidak ada {@code WebApplicationInitializer} implementasi ditemukan. * <p> Dengan asumsi bahwa satu atau lebih {@code WebApplicationInitializer} tipe terdeteksi, * mereka akan dipakai (dan <em> diurutkan </em> jika@{@link * org.springframework.core. Kemudian {@link WebApplicationInitializer#Onstartup (servletContext)} * Metode akan dipanggil pada setiap contoh, mendelegasikan {@code servletContext} seperti itu * bahwa setiap contoh dapat mendaftar dan mengkonfigurasi servlet seperti spring * {@code DispatcherServlet}, listener seperti springe {{@code dispatcherServer}, listener seperti springe {@code @code dispatcherServer}, pendengar {springe {{@code @code@ seperti filter. OnStartup (set <class <? >> WebAppInitializerClasses, ServletContext ServletContext) melempar servletException {List <EndiclicationInitializer> Inisialisasi = LinkedLists baru <webslicationInizer> (); Be defend: Some servlet containers provide us with invalid classes, // no matter what @HandlesTypes says... if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { //Create instances for all WebApplicationInitializer types and add ke koleksi inisialisasi.add ((WebApplicationInitializer) waiclass.newinstance ()); terdeteksi pada classpath "); return;} servletcontext.log (initializers.size () +" spring WebApplicationInitiizers terdeteksi di classpath "); annotationAwareOrderComparator.sort (inisialisasi); // memanggil metode inisialisasi: inisialisasi WebEpplicationInlizer. initializer.onsartup (servletContext);}}}Dalam komentar panjang di atas, Anda dapat melihat bahwa SpringServletContainerInitializer melewati semua kelas WebApplicationInitializer Type yang dianotasi oleh @handlestypes (WebApplicationInitializer.class) ke dalam parameter yang ditetapkan dari metode Onstartup, dan membuat instance untuk jenis aplikasi web ini dengan refleksi;
④ Metode di akhir, setiap WebApplicationInitilizer Implementation memanggil metode Onstartup sendiri
⑤ WebApplicationInitializer memiliki kelas implementasi abstrak springbooterervletinitializer (ingat kami mewarisi kelas abstrak ini), dan metode onStartup dari setiap contoh WebApplicationInitializer (termasuk springbootervletinitializer) akan disebut:
Publik Abstrak Kelas SpringbootServletInitializer mengimplementasikan WebApplicationInitializer {// kode lain ... @Override public void onStartup (servletContext servletContext) melempar servletException {// inisialisasi logger. // Buat IOC Container WebApplicationContext rootAppContext = createrOtApplicationContext (servletContext); if (rootAppContext! = null) {servletContext.addlistener (contextLoaderListener baru (rootappContext) {@Override public void contextInitialized (event servletContextEvent) {// no-op karena konteks aplikasi sudah diinisialisasi}}}); } else {this.logger.debug ("No ContextLoaderListener terdaftar, sebagai" + "createroTapplicationContext () tidak" + "mengembalikan konteks aplikasi"); }} Protected WebApplicationContext CreaterOtApplicationContext (ServletContext ServletContext) {// Buat pembangun aplikasi Spring dan atur properti yang relevan SpringApplicationBuilder builder = CreateSpringApplicationBuilder (); StandardServletenvironment Environment = New StandardServletenvironment (); Environment.InitPropertySources (ServletContext, null); builder.environment (lingkungan); builder.main (getClass ()); ApplicationContext Parent = GetExistingRootWebApplicationContext (ServletContext); if (induk! = null) {this.logger.info ("Konteks root sudah dibuat (menggunakan sebagai induk)."); servletContext.setAttribute (WebApplicationContext.root_web_application_context_attribute, null); builder.Initializers (ParentContextApplicationContextInitializer baru (Parent)); } builder.Initializers (servletContextAppLicationContextInitializer baru (servletContext)); builder.contextClass (AnnotationConfigembedDedWebApplicationContext.class); // Setelah memanggil metode konfigurasi dan membuat proyek web tipe perang, karena subclass dari springbootervletInitializer mengesampingkan metode konfigurasi, metode konfigurasi yang kami definisikan sebagai overrides disebut di sini. Builder = configure (builder); // Aplikasi pegas dibangun melalui aplikasi springApplication builder = builder.build (); if (application.getSources (). isEmpty () && annotationutils .findannotation (getClass (), configuration.class)! = null) {application.getSources (). add (getClass ()); } Assert.state (! Application.getSources (). IsEmpty (), "Tidak ada sumber aplikasi spring yang telah ditentukan. Entah mengesampingkan metode konfigurasi" + "atau tambahkan anotasi @configuration"); // Pastikan halaman kesalahan terdaftar jika (this.RegisterErrorPagefilter) {application.getSources (). Tambah (errorPagefilterConfiguration.class); } // Mulai Aplikasi Spring Return Run (Aplikasi); } // Aplikasi Spring dimulai, membuat dan mengembalikan WebAppLicationContext Run (Aplikasi SpringApplication Application) {return (WebApplicationContext) Application.run (); }}Ketika instance SpringbootServletInitializer mengeksekusi metode Onstartup, metode RUN akan dieksekusi melalui metode CreaterOtApplicationContext. Proses selanjutnya sama dengan proses menjalankan aplikasi yang dimulai dalam bentuk paket JAR. Wadah IOC akan dibuat secara internal dan dikembalikan. Namun, aplikasi dalam bentuk paket perang tidak akan lagi membuat wadah servlet selama proses pembuatan wadah IOC.
Meringkaskan
Di atas adalah seluruh konten artikel ini. Saya berharap konten artikel ini memiliki nilai referensi tertentu untuk studi atau pekerjaan semua orang. Jika Anda memiliki pertanyaan, Anda dapat meninggalkan pesan untuk berkomunikasi. Terima kasih atas dukungan Anda ke wulin.com.