Prefacio
Este artículo presenta principalmente el contenido relevante sobre el proceso de inicio y los principios de Servlet en Spring Boot. No diré mucho a continuación, echemos un vistazo a la introducción detallada juntos.
Proceso de inicio y principios:
1 Método de ejecución de la aplicación de arranque de primavera
Stopwatch stopwatch = new StopWatch (); stopwatch.start (); ConfiguableApplicationContext context = null; Analizadores de fallurayalzers = nulo; configureheadlessproperty (); SpringApplicationRunlisteners oyentes = GetRunListeners (args); oyentes.starting (); Pruebe {ApplicationArGuments ApplicationArGuments = new DefaultApplicationAarGuments (args); ConfigurableNenvironment Environment = prepareEnvironment (oyentes, ApplicationArGuments); Banner PrintedBanner = printbanner (entorno); // Cree un contexto de contenedor AplicationContext = CreateApplicationContext (); analizadores = new FauseAnalyzers (contexto); PrepareContext (contexto, entorno, oyentes, ApplicationArGuments, PrintedBanner); // Actualizar el contenedor IOC RefreshContext (contexto); AfterRefresh (contexto, ApplicationArGuments); oyentes. Finished (contexto, nulo); stopwatch.stop (); if (this.logstartupinfo) {nuevo startupinfologger (this.mainapplicationClass) .logstarted (getApplicationLog (), stopwatch); } contexto de retorno; } catch (throwable ex) {handlerunfailure (contexto, oyentes, analizadores, ex); tirar nueva IllegalStateException (EX); }2 CreateApplicationContext (): cree un contenedor IOC. Si se trata de una aplicación web, cree un contenedor IOC de AnnotationConfigembedDedWebApplication. Si no es así, cree un contenedor IOC de AnnotationConfigApplication.
public static final cadena default_context_class = "org.springframework.context". + "Annotation.AnnotationConfigApplicationContext"; /** * El nombre de clase del contexto de la aplicación que se utilizará de forma predeterminada para entornos web *. */ public static final String Default_web_context_class = "org.springframework". + "boot.context.embedded.annotationConfigembedDedwebApplicationContext"; protegido ConfigureBableApplicationContext CreateApepplicationContext () {Class <?> ContextClass = this.ApplicationContextClass; if (contextclass == null) {try {// Cree diferentes contenedores IOC de acuerdo con el entorno de la aplicación contextclass = class.forname (this.webenvironment? default_web_context_class: default_context_class); } Catch (ClassNotFoundException ex) {Throw New IlegalStateException ("No se puede crear una aplicación predeterminada," + "Especifique una aplicación AplicationContexsss", ex); }} return (configuableApplicationContext) beanutil.instantiate (contextClass); }3 RefreshContext (context) El arranque de resorte actualiza el contenedor IOC (cree objetos de contenedor, inicialice el contenedor y cree cada componente del contenedor)
privado void refreshContext (ContextureSaplApplicationContext context) {refresh (context); if (this.RegisterShutdownHook) {try {context.RegisterShutdownHook (); } Catch (AccessControlException ex) {// no está permitido en algunos entornos. }}}}4 actualizar (contexto); Actualice el contenedor IOC que acaba de crear
Protected void actual (ApplicationContext ApplicationContext) {ASSERT.IsInStanceOf (AbstractApplicationContext.Class, ApplicationContext); ((AbstractApplicationContext) ApplicationContext) .Refresh (); }5. Llame al método de la clase principal FRESH ()
public void refresh () lanza Beansexception, ilegalstateException {object var1 = this.StartUpshutDownmonitor; sincronizado (this.startupshutdownmonitor) {this.prepareFresh (); ConfiguableListableBeanFactory beanFactory = this.obtainfreshBeanFactory (); this.PreparebeanFactory (BeanFactory); intente {this.PostProcessBeanFactory (BeanFactory); this.invokeBeanFactoryPostProcessors (BeanFactory); this.RegisterBeanPostProcessors (BeanFactory); this.initMessageSource (); this.initApplicationEventMultCaster (); this.onrefresh (); this.RegisterListeners (); this. this.finishRefresh (); } Catch (Beansexception var9) {if (this.logger.IswarnenAnculed ()) {this.logger.warn ("Excepción encontrada durante la inicialización del contexto - Cancelando el intento de actualización:" + var9); } this.destroyBeans (); this.CancelRefresh (VAR9); arrojar var9; } finalmente {this.resetCommoncaches (); }}}6 El método OnRefresh del subclase incrustadowebapplicationContext de la clase matriz abstracta abstractApplicationContext
@Override protegido void onRefresh () {super.onrefresh (); intente {createEmbedDedServletContainer (); } capt (showable EX) {lanzar nueva aplicaciónContextException ("No se puede iniciar el contenedor integrado", ex); }}7 En el createEmbedDedServletContainer, se obtendrá la fábrica de contenedores de servlet integrado, y el servlet se crea a partir de la fábrica de contenedores
Void privado createEmbedDedServletContainer () {InceddedServletContainer localContainer = this.EmbedDedServletContainer; ServletContext localServletContext = getServletContext (); if (localContainer == NULL && LocalServletContext == NULL) {// Obtener fábrica de contenedores de servlet integrado INCNDEDServletContainerFactory ContainerFactory = GetEmbedDedServletContainerFactory (); // Obtenga el contenedor de servlet incrustado correspondiente basado en la fábrica de contenedores. } else if (localServletContext! = null) {try {getSelfInitializer (). OnStartUp (localServletContext); } Catch (ServLetException ex) {tire nueva aplicaciónContextException ("no se puede inicializar el contexto de servlet", ex); }} initPropertySources (); }8 Obtener fábrica de contenedores de servlet desde el contenedor IOC
// IncreddedWebApplicationContext#getEmbedDedServletContainerFactory IncReddedServletContainerFactory GetEmbedDedServletContainerFactory () {// use los nombres de los bean para que no consideremos la string de Herarchy [] beanNames = GetBeanFactory (). if (beanNames.length == 0) {Throw New ApplicationContextException ("No se puede iniciar IncredDedWebApplicationContext debido a la falta de" + "InbeddedServletContainerFactory Bean."); } if (beannames.length> 1) {tire nueva aplicaciónContextException ("No se puede iniciar InbeddedWebApplicationContext debido a múltiples frijoles" + "incrustados de FuntainerFactory:" + StringUtils.ArrayToComMadelimitedString (BeanNames)); } return getBeanFactory (). getBean (beannames [0], increddedservletContainerFactory.class); }9 Use la fábrica de contenedores de servlet para obtener contenedores de servlet incrustados. Qué fábrica de contenedores para usar depende de la dependencia del entorno de configuración
this.EmbedDedServletContainer = ContainerFactory .getEmbedDedServletContainer (GetSelfInitializer ());
10 El proceso de creación anterior inicia primero el contenedor IOC, luego inicia el contenedor de servlet incrustado y luego recupera los objetos restantes que no se crean en el contenedor IOC, como el controlador que creó usted mismo.
// Instanciar todos los singletons restantes (innato de inicio). finkbeanFactoryInitialization (beanFactory);
El void protegido protegido BeanFactoryInitialization (configEableListableBeanFactory BeanFactory) {// Inicializar el servicio de conversión para este contexto. 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)); } // Registre un resolución de valor incrustado predeterminado si no hay postprocesador de bean // (como un bean de propiedad de propiedad en el bean) registrado antes: // en este punto, principalmente para la resolución en los valores de atributos de anotación. if (! beanFactory.hasembedDedValueResolver ()) {beanFactory.AdDembedDedValueresolver (new StringValueResolver () {@Override public String resolvingValue (String StrVal) {return getenVironment (). ResolvePlaceHolders (strval);}}}); } // Inicializa los frijoles LoadTimeVeraware temprano para permitir registrar sus transformadores temprano. String [] weaverawarenames = beanFactory.getBeanNamesFortype (LoadTimeWeaveraware.class, falso, falso); for (string weaverawarename: weaverawarenames) {getBean (weaverawarename); } // deja de usar el cargador de clases temporal para el tipo de coincidencia. BeanFactory.SettempClassLoader (NULL); // Permitir almacenamiento en caché todos los metadatos de definición de frijoles, no esperar más cambios. BeanFactory.Freezeconfiguration (); // Instanciar todos los singletons restantes (innato de inicio). BeanFactory.PreinstantiatesEntletons (); }Echa un vistazo al método preinstantiatesingletons
public void preinstantiatesingletons () lanza Beansexception {if (this.logger.isdeBugeNabled ()) {this.logger.debug ("singletons preinstantantes en" + this); } List <String> beanNames = new ArrayList (this.BeanDefinitionNames); Iterador 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 (); Object SingletonInstance = this.getSingleton (beanName); if (SingletonInstance instancia de SmartInitializingingSingleton) {Final SmartInitializingsingLeton SmartSingleton = (SmartInitializingingSingleton) SingletonInstance; if (system.getSecurityManager ()! = NULL) {AccessController.DoPrivileged (new PrivilegedAction <SPET> () {public object Run () {SmartSingleton.AfterSingLetonSinstantiate (); return null;}}, this.getAccessControlContext ()); } else {SmartSingleton.AfterSingLetonsInstantiated (); } } devolver; } 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 isEageerInit; if (system.getSecurityManager ()! = NULL && Factory instancia de SmartFactoryBean) {isEageInit = (((Boolean) AccessController.Doprivileged (New PrivilegEdaction <Boolean> () {public boolean run () {return (SmartFactoryBean) Factory) .IsageGerinit ();}},,, this.getAccessControlContext ())). booleanValue (); } else {isEageRInit = Factory instancia de SmartFactoryBean && ((SmartFactoryBean) Factory) .ISeAgerInit (); } if (isEageRInit) {this.getBean (beanName); }} else {// registrar bean this.getBean (beanName); }}}}}}}}}}Use el método GetBean para crear todas las instancias no creadas a través de la reflexión.
Uso de contenedores de servlet incrustados:
Ventajas: simple, portátil
Desventajas: JSP no admite por defecto, la optimización y la personalización son más complicadas
Pasos para usar un contenedor de servlet externo:
1. El proyecto de guerra debe ser creado y se requiere la estructura del directorio del proyecto web de Jianhao.
2 El alcance de dependencia de Tomcat incrustado especifica proporcionada
3 Escriba una subclase de clase SpringBootServletinitializer y anule el método Configurar
ServletInitializer de clase pública extiende SpringBootServletInitializer {@Override SpringApplicationBuilder Configure (SpringApplicationBuilder Application) {Return Application.sources (SpringBoot04WebJspApplication.class); }}4 Inicie el servidor
La diferencia entre el paquete de jar de arranque y el paquete de guerra
Paquete JAR: ejecute el método Ejecutar de SpringBootApplication, inicie el contenedor IOC y luego cree un contenedor de servlet incrustado
Paquete de guerra: Primero, inicie el servidor Servlet, el servidor inicia la aplicación SpringBoot (SpringBootServletinitizer) y luego inicia el contenedor IOC
Servlet 3.0+ reglas
1. Inicio del servidor (inicio de la aplicación web), se creará la instancia de ServletContainerlnitializer en todos los paquetes JAR en la aplicación web actual.
2 La implementación de ServletContainerInitializer se coloca en la carpeta Meta-INF/Servicios del paquete JAR
3 También puede usar la anotación @Handlestypes para cargar la clase especificada cuando se inicia la aplicación.
Proceso y principios externos de Tomcat
① Comienza Tomcat
② Según las reglas Servlet3.0+ descritas anteriormente, puede encontrar un archivo llamado javax.servlet.servletContainerInitializer en el módulo web de Spring, y el contenido del archivo es org.springframework.web.springservletContainerInitializer, que se utiliza para cargar la clase SpringServletContainerInitializer.
③ Vea la definición de SpringServletContainerInitializer
@Handlestypes (WebApplicationInitializer.class) public SpringServletContainerInitializer implementos ServletContainerInitializer { /** * Delegate las {@Code ServletContext} a cualquier {@Link WebApplicationInitializer} * Implementaciones presentes en el classpath de aplicaciones. * <p> porque esta clase declara@{@@Code HandLestypes (WebApplicationInitializer.class)}, * Servlet 3.0+ Los contenedores escanearán automáticamente el ClassPath para las implementaciones * de la interfaz de Spring {@Code WebAnsapplationInitializer} y proporcionará el conjunto de todos los * tipos de tipos a los {@@code webappiniAniatizerClasses} de este metá. * <p> Si no se encuentran {@code webapplicationInitializer} implementaciones en el classpath, * este método es efectivamente un no-op. Se emitirá un mensaje de registro de nivel de información notificando * el usuario que se ha invocado {@code servletContainerInitializer} pero que * no se encontraron {@code webapplicationInitializer}. * <p> Suponiendo que se detectan uno o más tipos {@code webApplicationInitializer}, * se instanciarán (y <em> Orded </em> si el@{@link * org.springframework.core.annotation.order @order} annotation ha estado presente o * el {@@link org.springFringFrame.core.core.core. implementado. entonces el método {@link webApplicationInitializer#onStartUp (servletContext)} * se invocará en cada instancia, delegando el {@code servletContext} tales * que cada instancia puede registrar y configurar servlets como el spring * {@code}, oyentes como los oyentes como el spring {@code contexterlister}, * o otros oyentes de Servlet, * o otros oyentes de Servlet, * o otros oyentes de Spring. Componentes como filtros. OnStartUp (set <class <? >> WebAppinitializerClasses, servletContext ServletContext) lanza ServletException {list <WebApplicationInitializer> Initializers = new LinkedList <WebApplicationInitializer> (); Defender: algunos contenedores de servlet nos proporcionan clases no válidas, // no importa lo que diga @HandlestyPes ... if (! waiclass.isinterface () &&! a la colección Initializers.Add ((WebApplicationInitializer) waiclass.newinstance ()); en classpath "); return;} servletContext.log (inicializers.size () +" Spring WebApplicationInitializadores detectados en classpath "); annotationAareRorderComparator.sort (inicializadores); inicializer.onstartup (servletContext);En el comentario largo anterior, puede ver que SpringServletContainerInitializer pasa todas las clases de Tipo de Aplicación WebAncationInitializadora anotada por @HandlestyPes (WebApplicationInitializer.class) en el parámetro establecido del método OnStartUp, y crea casos para estos tipos de aplicaciones WebApplicationInitializer por reflexión;
④ Método Al final, cada implementación de AplicationInitilizer de web llama su propio método OnStartUp
⑤ WebApplicationInitializer tiene una clase de implementación abstracta SpringBootServletInitializer (recuerde que heredamos esta clase abstracta), y se llamará el método OnStartUp de cada instancia de aplicaciones web (incluido SpringBootServletinitializer):
Public Abstract Class SpringBootServletInitializer implementa WebApplicationInitializer {// Otro código ... @Override public void onStartup (servletContext ServletContext) lanza ServletException {// Inicialización de logger se aplaza en caso de que se ordene // LogServletContextInitializer se está utilizando this.logger = logFactory.getLog (GetCleSs (); // Crear contenedor IOC WebApplicationContext RootAppContext = CreaterotapplicationContext (servletContext); if (rootAppContext! = NULL) {servletContext.addListener (new contextLoLoGerListener (rootAppContext) {@Override public void contextInitialized (servletContextEvent Event) {// no-op porque el contexto de la aplicación ya está inicializado}}); } else {this.logger.debug ("no contextLoLoGerListener registrado, como" + "createrootapplicationContext () no" + "devolver un contexto de aplicación"); }} Profected WebApplicationContext CreaterotapplicationContext (servletContext ServletContext) {// Cree el constructor de aplicaciones de Spring y establezca las propiedades relevantes SpringApplicationBuilder Builder = CreateSpringAplicationBuilder (); StandardSardServletEnvironment Environment = New StandardServletEnvironment (); ambiente.initpropertySources (servletContext, null); constructor.environment (medio ambiente); builder.main (getClass ()); ApplicationContext Parent = getExistingRootWebApplicationContext (servletContext); if (parent! = null) {this.logger.info ("contexto raíz ya creado (usando como parent)"); servletContext.setAttribute (WebApplicationContext.Root_Web_Application_Context_Attribute, null); builder.initializers (new ParentContextApplicationContextinitializer (parent)); } builder.initializers (new ServletContextApplicationContextInitializer (servletContext)); Builder.ContextClass (AnnotationConfigembedDedWebApplicationContext.Class); // Después de llamar al método Configurar y crear un proyecto web de tipo de guerra, ya que la subclase de SpringBootServletinitializer anula el método Configuración, el método de configuración que definimos anulaciones se llama aquí. Builder = configure (Builder); // Una aplicación de resorte se construye a través de la aplicación Builder SpringApplication = Builder.Build (); if (application.getSources (). isEmpty () && annotationUtils .findannotation (getClass (), configuration.class)! = NULL) {Application.getSources (). Add (getClass ()); } Afirmar.state (! Application.getSources (). IsEmpty (), "No se han definido fuentes de SpringApplication. Ya sea anular el método" + "de configuración o agregar una anotación @Configuration"); // Asegúrese de que las páginas de error estén registradas si (this.RegistererRorPageFilter) {Application.getSources (). ADD (ERRORPAGEFILTERCONFIGURATION.Class); } // Inicie la ejecución de retorno de la aplicación Spring (aplicación); } // La aplicación Spring comienza, crea y devuelve el Contenedor IOC protegido WebApplicationContext run (SpringApplication Application) {return (WebApplicationContext) Application.run (); }}Cuando la instancia SpringBootServletInitializer ejecuta el método ONSTARTUP, el método Ejecutar se ejecutará a través del método CreateRoTApplicationContext. El siguiente proceso es el mismo que el proceso de ejecución de la aplicación iniciada en forma de un paquete JAR. El contenedor del COI se creará internamente y se devolverá. Sin embargo, la aplicación en forma de un paquete de guerra ya no creará el contenedor de servlet durante el proceso de creación del contenedor IOC.
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.