Préface
Cet article présente principalement le contenu pertinent sur le processus et les principes de démarrage du servlet dans Spring Boot. Je ne dirai pas beaucoup ci-dessous, jetons un coup d'œil à l'introduction détaillée ensemble.
Processus de démarrage et principes:
1 Méthode d'exécution de démarrage de l'application Spring Boot
Stopwatch stopwatch = new stopwatch (); stopwatch.start (); ConfigurableApplicationContext context = null; Analyseurs de FailureArAnalysers = NULL; configureHeadlessProperty (); SpringApplicationRunListeners auditeurs = getRunListeners (args); auditeurs.starting (); essayez {applicationArguments applicationArguments = new defaultApplicationArguments (args); Environnement Configurableenvironment = Préparer Environment (auditeurs, applicationArguments); Banner Printedbanner = Printbanner (environnement); // Créer un conteneur applicationContext conteneur = createApplicationContext (); analyseurs = nouveaux échecs de défaillance (contexte); prepareContext (contexte, environnement, auditeurs, applicationArguments, imprimébanner); // Refresh IOC Container RefreshContext (Context); AfterRefresh (contexte, applicationArguments); écouteurs finis (contexte, null); stopwatch.stop (); if (this.logStartupInfo) {nouveau startupInfologger (this.mainApplicationClass) .logStarted (getApplicationLog (), stopwatch); } Return Context; } catch (Throwable ex) {handlerunfailure (contexte, auditeurs, analyseurs, ex); jeter un nouvel illégalstateException (ex); }2 createApplicationContext (): Créez un conteneur IOC. S'il s'agit d'une application Web, créez un conteneur IOC d'AnnotationConfigembedDedWebApplication. Si ce n'est pas le cas, créez un conteneur IOC d'AnnotationConfigApplication.
public static final string default_context_class = "org.springframework.context." + "Annotation.annotationConfigApplicationContext"; / ** * Le nom de classe du contexte d'application qui sera utilisé par défaut pour les environnements Web *. * / public static final String default_web_context_class = "org.springframework." + "boot.context.embedded.annotationConfigeMedDedWebApplicationContext"; Protection ConfigurableApplicationContext CreateApplicationContext () {class <?> contextClass = this.applicationContextClass; if (contextClass == null) {try {// créer différents conteneurs IOC en fonction de l'environnement d'application contextClass = class.forname (this.webenvironment? Default_web_context_class: default_context_class); } catch (classNotFoundException ex) {throw new illégalStateException ("ne peut pas créer une application par défaut," + "Veuillez spécifier une applicationContextClass", ex); }} return (configurableApplicationContext) beanutils.Instantiate (contextClass); }3 RefreshContext (Context) Spring Boot Refreshs le conteneur IOC (Créez des objets de conteneur, initialisez le conteneur et créez chaque composant du conteneur)
Private void RefreshContext (ConfigurableApplicationContext Context) {Refresh (context); if (this.registerShutdownHook) {try {context.registerShutdownHook (); } catch (AccessControlexception ex) {// pas autorisé dans certains environnements. }}}}4 actualisation (contexte); Actualiser le conteneur IOC que vous venez de créer
Protected void Refresh (ApplicationContext ApplicationContext) {ASSERT.IsinstanceOf (AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) ApplicationContext) .Refresh (); }5. Appelez la méthode de Rafresh () de la classe parentale ()
public void Refresh () lève BeanSexception, illégalStateException {objet var1 = this.startupShutdownmonitor; synchronisé (this.startupShutdownMonitor) {this.PrearereFresh (); ConfigurableListableBeAnfactory beanfactory = this.obtainfreshbeanfactory (); this.prepareBeAnfactory (beanfactory); essayez {this.PostProcessBeanFactory (beanfactory); this.invokebeanfactoryPostProcessors (Beanfactory); this.RegisterBeanPostProcessors (Beanfactory); this.InitMessagesource (); this.initApplicationEventMulticaster (); this.OnRefresh (); this.RegisterListeners (); this.FinishBeanfactoryInitialisation (Beanfactory); this.finishRefresh (); } catch (beanSexception var9) {if (this.logger.iswarnenabled ()) {this.logger.warn ("Exception rencontrée lors de l'initialisation de contexte - Annulation de rafraîchissement de la tentative:" + var9); } this.destroybeans (); this.cancelRefresh (var9); lancer var9; } enfin {this.resetCommonCaches (); }}}6 La méthode onRefresh de la sous-classe EmbeddedWebApplicationContext de la classe parent abstraite AbstractApplicationContex
@Override Protected void onRefresh () {super.OnRefresh (); essayez {CreateMedDedServletContainer (); } catch (Throwable ex) {Throw New ApplicationContexTexception ("Implabsité de démarrer un conteneur embarqué", ex); }}7 Dans le CreateEmbeddedServletContainer, l'usine de conteneurs de servlet intégrée sera obtenue et le servlet est créé à partir de l'usine de conteneurs
private void CreateEmbedDedServletContainer () {EmbedDedServletContainer LocalContainer = this.embeddedServletContainer; ServletContext localServletContext = getServletContext (); if (localContainer == null && localServletContext == null) {// get embedded Servlet Container Factory EmbedDedServletContainerFactory contenerFactory = GetEmbedDeservletContainerFactory (); // obtient le conteneur servlet intégré correspondant basé sur l'usine de conteneurs this.embeddedServletContainer = ContainerFactory .geteMedDeDServletContainer (getSelnitializer ()); } else if (localServletContext! = null) {try {getSelninitializer (). OnStartup (localServletContex); } catch (servlexception ex) {lancez une nouvelle applicationContexTexception ("Impossible d'initialiser le contexte du servlet", ex); }} initpropertysources (); }8 Get Servlet Container Factory du conteneur IOC
//EmbeddedWebApplicationContext#getEmbeddedServletContainerFactory protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory() .getBeanNamesForty (EmbedDeDServletContainerFactory.class); if (beanNames.length == 0) {lancez une nouvelle applicationContexTexception ("Impossible de démarrer EmbedDedWebApplicationContext en raison de" + "EmbedDedServletContainerFactory Bean."); } if (beanNames.length> 1) {lancez une nouvelle applicationContexTexception ("Impossible de démarrer EmbedDedWebApplicationContext en raison de plusieurs beans" + "EmbedDeservletContainerFactory:" + stringUtils.ArrayToComadelimitedString (BeanNames)); } return getBeAnfactory (). getbean (beannames [0], embedDedServletContainerFactory.class); }9 Utilisez l'usine de conteneurs de servlet pour obtenir des conteneurs de servlet intégrés. Quelle usine de conteneurs à utiliser dépend de la dépendance à l'environnement de configuration
this.embeddedServletContainer = ContainerFactory .GetEmbedDedServletContainer (getSelLniitializer ());
10 Le processus de création ci-dessus démarre d'abord le conteneur IOC, puis démarre le conteneur servlet intégré, puis récupère les objets restants qui ne sont pas créés dans le conteneur IOC, comme le contrôleur que vous avez créé par vous-même.
// Instancier tous les singletons restants (non-paresseux). FinishBeanFactoryInitialisation (Beanfactory);
Protégé void finalBeanFactoryInitialization (configurableListableBeanFactory Beanfactory) {// Initialiser le service de conversion pour ce contexte. 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); } // Enregistrez un résolveur de valeur intégré par défaut si aucun post-processeur de bean // (comme un propriétéPlaceHolderConfigurer Bean) s'est enregistré avant: // à ce stade, principalement pour la résolution dans les valeurs d'attribut d'annotation. if (! beanfactory.hasembeddedvalueresolver ()) {beanfactory.addembeddedvalueresolver (new StringValueResolver () {@Override public String ResolvestringValue (String strval) {return getEnvironment (). ResolvePlaceHolders (Strval);}}); } // Initialisez les haricots LoadtimeVeaveware tôt pour permettre d'enregistrer leurs transformateurs tôt. String [] weaverawarenames = beanfactory.getBeanNamesForty (loadtimeweaveaware.class, false, false); for (String WeaverawaRename: WeaverawaRenames) {getBean (WeaverawaRename); } // Arrêtez d'utiliser le chargeur de classe temporaire pour la correspondance de type. beanfactory.setTempClassloader (null); // Autoriser la mise en cache de toutes les métadonnées de définition des haricots, sans s'attendre à d'autres modifications. beanfactory.freezeconfiguration (); // Instancier tous les singletons restants (non-paresseux). beanfactory.preinStantiaSingLetons (); }Découvrez la méthode préinstantiatesingletons
public void preinstantiateSingLeTons () lève BeanSexception {if (this.logger.isdebugeNable ()) {this.logger.debug ("singletons pré-instanciation dans" + this); } List <string> beanNames = new ArrayList (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 (); Objet singletonInstance = this.getSingleton (beanname); if (singletoninstance instance of smartInitializingSingleton) {final smartInitializingSingleton smartSingleton = (smartInitializingSingleton) singletonInstance; if (System.getSecurityManager ()! = null) {AccessController.Dopriviled (new privilEdAction <Bject> () {public Object run () {SmartSingleton.AftersingletOnSinStantiated (); return null;}}, this.getAcsseControlContext ()); } else {smartSingleton.AftersingLetSInstantiated (); } } retour; } 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); booléen iseeagerinit; if (System.getSecurityManager ()! = null && Instance d'usine de SmartFactoryBean) {iseAgerNit = ((booléen) AccessController.Doprivileged (nouveau privilEGEGAGE <Boolean> () {public boolean run () {return ((smartFactoryBean) factory) .isegerInit ();},,,) this.getAccessControlContext ())). BooleanValue (); } else {iseeagerinit = instance d'usine de SmartFactoryBean && ((SmartFactoryBean) Factory) .IseAgerInit (); } if (iseeAgerInit) {this.getBean (beanname); }} else {// enregistrer le bean this.getBean (beanname); }}}}}}}}}}Utilisez la méthode GetBean pour créer toutes les instances non créées via la réflexion.
Utilisation de conteneurs de servlet intégrés:
Avantages: simple, portable
Inconvénients: JSP ne prend pas en charge par défaut, l'optimisation et la personnalisation sont plus compliquées
Étapes pour utiliser un conteneur de servlet externe:
1. Le projet de guerre doit être créé et la structure du répertoire du projet Web Jianhao est requise.
2 Étendue de dépendance Tomcat intégrée Spécifies fournis
3 Écrivez une sous-classe de classe SpringbootServitializer et remplacez la méthode de configuration
La classe publique ServleTinitializer étend SpringbootServletInitializer {@Override Protected SpringApplicationBuilder Configure (application SpringApplicationBuilder) {return Application.Sources (Springboot04WebjSpApplication.Class); }}4 Démarrez le serveur
La différence entre le package de pas de départ et le package de guerre
Package JAR: Exécutez la méthode d'exécution de SpringbootApplication, démarrez le conteneur IOC, puis créez un conteneur servlet intégré
Package de guerre: Tout d'abord, démarrez le serveur Servlet, le serveur démarre l'application Springboot (SpringbootServletinitizer), puis démarre le conteneur IOC
Règles de servlet 3.0+
1. Startup de serveur (startup d'application Web), l'instance ServletContainerlnitializer dans tous les packages JAR de l'application Web actuelle sera créée.
2 La mise en œuvre de ServletContainerinitializer est placée dans le dossier Meta-Inf / Services du package JAR
3 Vous pouvez également utiliser l'annotation @Handlestypes pour charger la classe spécifiée lorsque l'application est démarrée.
Processus et principes de Tomcat externes
① Commencez Tomcat
② Selon les règles de servlet3.0 + décrites ci-dessus, vous pouvez trouver un fichier nommé javax.servlet.servletContainerinitializer dans le module Web de Spring, et le contenu du fichier est org.springframework.web.springSertContainerinitializer, qui est utilisé pour charger la classe SpringSernitinitializer.
③ regarder à la définition de SpringservletContainerinitializer
@Handlestypes (WebApplicationInitializer.Class) Classe publique SpringServletContainerinitializer implémente ServletContainerinitializer {/ ** * Déléguer le {@code servletContext} à tout {@link webApplicationInitializer} * Implémentations présentes sur le silence de classe. * <p> Parce que cette classe déclare @ {@ Code Handlestypes (WebApplicationInitializer.Class)}, * Servlet 3.0+ Les conteneurs analyseront automatiquement le chemin de classe pour les implémentations * de Spring's {@code webApplicationInitializer} Interface et fourniront l'ensemble de tous les * types de types de types {@code webAppintializerSer}. * <p> Si aucune {@code webApplicationInitializer} les implémentations se trouvent sur le CLASSPATH, * Cette méthode est effectivement un non-op. Un message de journal de niveau d'info sera émis en indiquant * l'utilisateur que le {@code servletContainerinitializer} a en effet été invoqué mais que * non {@code webApplicationInitializer} les implémentations ont été trouvées. * <p> En supposant qu'un ou plusieurs types {@code webApplicationInitializer} sont détectés, * ils seront instanciés (et <em> triés </em> si l'annotation @ {@ link * org.springframe.Core.annotation.order @Order} est présent ou * l'interface @Link Org.spring implémenté. tels que les filtres. OnStartup (set <class <? >> webAppinitializerClasses, ServletContext ServletContext) lance ServletException {list <webApplicationInitializer> initialisers = new LinkedList <webApplicationInitializer> (); Defend: Certains contenants de servlets nous fournissent des classes non valides, // peu importe ce que @HandleSTypes dit ... if (! waiclass.isinterface () &&! modificateur.isabstract (waiclass.getModificaires ()) && webapplicationInitializer.class.isassignablefrom (waiclass) {essai La collection initialisers.add ((webApplicationInitializer) waiclass.NewInstance ());} Catch (Thrownable Ex) {Throw New Servlexception ("Échec de l'instanciation de la classe WebAPLICIALIATION", ex); CLASSPATH "); return;} servletContext.log (initialisers.size () +" Spring WebApplicationInitialisers détecté sur ClassPath "); AnnotationAwareOrderCompéateur.Sort (initialiseurs); // appelant la méthode OnStartup de chaque webapplicationInitializer instance for (webApplicationInTitizer initializer: Initialisers) {initialise. }}}Dans le long commentaire ci-dessus, vous pouvez voir que SpringServletContainerinitializer transmet toutes les classes de type d'application indicativement annotée par @handlestypes (WebApplicationInitializer.class) dans le paramètre SET de la méthode OnStartup, et crée des instances pour ces types de l'application Web par réflexion;
④ Méthode Au fin
⑤ WebApplicationInitializer a une classe d'implémentation abstraite SpringbootServleTinitializer (rappelez-vous que nous avons hérité de cette classe abstraite), et la méthode OnStartup de chaque instance de l'application Web (y compris SpringbootServletinitializer) sera appelée:
Classe abstrait public SpringbootServletInitializer implémente WebApplicationInitializer {// Autre code ... @Override public void OnStartup (ServletContext ServletContext) lance ServletException {// Logger L'initialisation est différée dans le cas où une commande // LogServletContexInitializer est utilisée this.logger = logfactory.getLog (getClass);); // Créer un conteneur IOC WebApplicationContext rootAppContext = CreaTootApplicationContext (ServletContext); if (rootAppContext! = null) {servletContext.addListener (new ContextloadEListener (rootAppContext) {@Override public void contextinitialialialialized (ServletContexTevent Event) {// non-op car le contexte d'application est déjà initialisé}}); } else {this.logger.debug ("Aucun contexteListener enregistré, en tant que" + "CreaterootApplicationContext () n'a pas" renvoyé un contexte d'application "); }} webApplicationContext protégé CreaTootoOtApplicationContext (ServletContext ServletContext) {// Créer le Spring Application Builder et définir les propriétés pertinentes SpringApplicationBuilder Builder = CreateSpringApplicationBuilder (); Environnement StandardervleTenvironment = Nouveau StandardServleTenvironment (); Environment.InitPropertySources (ServletContext, null); builder.environment (environnement); builder.main (getClass ()); ApplicationContext parent = getExistRootWebApplicationContext (servletContext); if (parent! = null) {this.logger.info ("contexte racine déjà créé (en utilisant comme parent)."); servletContext.setAttribute (webApplicationContext.root_web_application_context_attribute, null); builder.Initializers (nouveau parentContextApplicationContexInitializer (parent)); } builder.inializers (nouveau servletContextApplicationContextInitializer (servletContext)); builder.contextClass (annotationConfigeMedDedWebApplicationContext.class); // Après avoir appelé la méthode de configuration et créé un projet Web de type guerre, puisque la sous-classe de SpringbootServletinitializer remplace la méthode de configuration, la méthode de configuration que nous avons définie les remplacements est appelée ici. Builder = configure (builder); // Une application Spring est construite via l'application SpringApplication Builder = builder.build (); if (application.getsources (). isempty () && annotationutils .findannotation (getClass (), configuration.class)! = null) {application.getsources (). add (getClass ()); } Assert.state (! Application.getsources (). IsEmpty (), "Aucune source SpringApplication n'a été définie. Soit remplacer la méthode" + "de configuration ou ajouter une annotation @configuration"); // Assurez-vous que les pages d'erreur sont enregistrées si (this.RegisterErrorPageFilter) {application.getsources (). Add (errorPageFilterConfiguration.class); } // Démarrer le rendement de l'application Spring (application); } // L'application Spring démarre, crée et renvoie le conteneur IOC Protected webApplicationContext run (application SpringApplication) {return (webApplicationContext) application.run (); }}Lorsque l'instance SpringbootServletInitializer exécute la méthode OnStartup, la méthode d'exécution sera exécutée via la méthode CreaterootApplicationContext. Le processus suivant est le même que le processus d'exécution de l'application démarrée sous la forme d'un package JAR. Le conteneur IOC sera créé en interne et retourné. Cependant, l'application sous la forme d'un package de guerre ne créera plus le conteneur servlet pendant le processus de création du conteneur IOC.
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.