Recientemente, tengo tiempo para optimizar la plataforma API abierta de la compañía. Cuando estaba escribiendo el paquete de jar, de repente me di cuenta de que estaba muy hábil al usar el arranque de primavera antes, pero nunca supe el principio inicial del frasco producido por Spring Boot. Luego desabroché el frasco esta vez y lo miré. Era realmente diferente de lo que imaginaba. El siguiente es un análisis completo del frasco descomprimido.
La aplicación del arranque de primavera no se publica. La estructura de una demostración más simple es similar. Además, la versión de Spring Boot que utilicé es 1.4.1. Hay otro artículo en Internet para analizar el inicio de Spring Boot Jar. Eso debe estar por debajo de 1.4, y el método de inicio también es muy diferente de la versión actual.
Después de la instalación de MVN Clean, cuando miramos en el directorio de destino, encontraremos dos paquetes JAR, de la siguiente manera:
xxxx.jarxxx.jar.original
Esto se atribuye al mecanismo de complemento de arranque de Spring, que convierte un frasco ordinario en un paquete de jar ejecutable, y xxx.jar.original es un paquete de jares producido por Maven. Estos se pueden encontrar en referencia al artículo en el sitio web oficial de Spring, de la siguiente manera:
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar
La siguiente es parte de la estructura del directorio del frasco producido por la aplicación de arranque de resorte, la mayoría de las cuales se omiten, y solo se muestran las partes importantes.
.├── Boot-Inf│ ├── Classes│ ├── Aplicación-Dev.Properties│ │ ├── Aplicación-PROD.Properties│ │ ├── Aplicación. │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └ └── Open│ │ │ │ │ │ │ │ └ └ └uto swaggerconfig.class│ │ │ │ │ │ │ └ └ └ └ └ └ └ └ └ └ └ └ │ │ │ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ └ │ │ │ │ │ │ └ └── swaggerConfig.class│ │ │ │ │ ├── oauth2│ │ │ │ ├ ├── Controler│ │ │ │ ├ ├ ├ Sapi └── Guru.css│ │ ├── Imágenes │ │── FBCover1200x628.png│ │ └ └── Newbannerboots_2.png│ └── Lib│ ├─ Accesors-Smart-1.1.Jar├─ Meta-Inf│ ├ ├ ├ ├. com.weibanGong.open│ └── Open-Server-Openapi│ ├── Pom.Properties│ └── Pom.xml└─ap Lanzador de lanzamiento de cajas de clase $ 1.class ├── la elunchedurlClassLoader.class ├── la eluncher.class ├── Archive │ ├── Archive $ Entry.Class │ ├─ige Archive $ EntryFilter.Class │ ├ ├─Classshass │ ├ ├ ├ ─ Explodedarquista $ 1.Class │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │class │ │ │ │class. ├── ExplodeDarchive $ FileEntryiterator $ EntryComparator.Class ├── ExplodedEnchive $ fileEntryiterator.class
Además de la clase que escribimos en la aplicación, este JAR también tiene un paquete ORG separado. Debe ser que la aplicación Spring Boot utilice el complemento Spring Boot para ingresar a este paquete, que es mejorar la etapa del paquete en el ciclo de vida de MVN. Es este paquete el que juega un papel clave en el proceso de inicio. Además, las diversas dependencias requeridas por la aplicación se ingresan en el JAR y se ingresa el paquete adicional de arranque de resorte. Este frasco que puede todo en uno también se llama fat.jar. Aquí siempre usaremos fat.jar para reemplazar el nombre del frasco.
En este momento, continuaremos mirando el archivo Manifest.mf en Meta-Inf, de la siguiente manera:
Versión manifiesta: 1.0IMPLEMENTATION-TITLE: Open :: Server :: OpenApiimplementation-Versión: 1.0-snapshotarchiver-version: Plexus ArchiverBuilt-by: xiaxuanimplementation-vendor-id: weibangongong.openspring-boot-version: 1.4.1.1.1relase-vendor-vendel Inc.Main-Class: org.springframework.boot.loader.propertieslawuncherstart-class: com.weibangong.open.openapi.springbootwebapplicationspring-classes: bootin-inf/classes/spring-boot-libl: boot-inf/lib/creating-by: apache maven maven 3.3.9build-jdk: 1.8.0_20implementation-url: http://maven.apache.org/open-server-openapi
La clase principal especificada aquí es un archivo de clase en el paquete que se ingresa por separado en lugar de nuestro programa de inicio, y luego el archivo Manifest.mf tiene una clase de inicio separada que especifica el programa de inicio de nuestra aplicación.
Primero encontramos la clase org.springframework.boot.loader.propertieslauncher, donde el método principal es:
public static void main (string [] args) lanza la excepción {PropertiesLauncher Launcher = new PropertiesLauncher (); args = Launcher.getArgs (args); Launcher.launch (args);}Verifique el método de lanzamiento. Este método se encuentra en el lanzador de clase principal y el método de lanzamiento de la clase principal es el siguiente:
Protected void lanzador (string [] args, string mainclass, classloader classloader) lanza la excepción {thread.currentThread (). setContextClassLoader (classLoader); this.CreateMainMethodrunner (MainClass, Args, ClassLoader) .run (); } Protected MainMethodrunner CreateMainMethodrunner (String MainClass, String [] args, classloader classloader) {return new MainMethodrunner (mainclass, args); }El método de lanzamiento finalmente llama al método CreateMeinMethodrunner, que instancias del objeto MainMethodrunner y ejecuta el método Ejecutar. Vamos al código fuente principal de Methodrunner, como sigue:
paquete org.springframework.boot.loader; import java.lang.reflect.method; public class MainMethodrunner {String final privado MainClassName; Cadena final privada [] args; public MainMethodrunner (String MainClass, String [] args) {this.MainClassName = mainClass; this.args = args == null? null: (string []) args.clone (); } public void run () lanza excepción {class mainclass = thread.currentThread (). getContextClassLoader (). LoadClass (this.MainClassName); Método mainmethod = mainclass.getDeClaredMethod ("main", nueva clase [] {String []. Class}); mainmethod.invoke ((objeto) nulo, nuevo objeto [] {this.args}); }}Verificando el método de ejecución, es muy fácil ejecutar la jarra de arranque de resorte y el análisis ha terminado básicamente.
5. El proceso de inicio del programa principal
Después de hablar sobre el proceso de inicio de JAR, hablemos sobre el proceso de inicio y carga del programa principal en la aplicación Spring Boot. Primero, veamos el método principal de la aplicación Spring Boot.
paquete cn.com.devh; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.cloud.client.discovery.enabledScovericliente; importar; importación; org.springframework.cloud.netflix.eureka.enedeurekaclient; import org.springframework.cloud.netflix.feign.enablefeignclients;/*** creado por Xiaxuan el 17/8/25. */@Springbootapplication@enablefeignClients@EnseateeureKaclientPublic Class A1ServiceApplication {public static void main (string [] args) {springapplication.run (a1serviceApplication.class, args); }}Vaya al método de ejecución en SpringApplication, como sigue:
/** * Ayudante estático que se puede usar para ejecutar una {@link SpringApplication} desde la fuente * especificada utilizando la configuración predeterminada. * @param fuente La fuente para cargar * @param args los argumentos de la aplicación (generalmente pasados desde un método principal de Java) * @return el en ejecución {@link applicationContext} */ public static configurureableApplicationContext run (fuente de objeto, cadena ... } /** * Ayudante estático que se puede usar para ejecutar una {@link SpringApplication} de las fuentes * especificadas utilizando la configuración predeterminada y los argumentos suministrados por el usuario. * @param fuentes Las fuentes para cargar * @param argumentan los argumentos de la aplicación (generalmente se pasan de un método principal de Java) * @return las fuentes en ejecución {@link ApplicationContext} */ public static ConfigurableApplicationContext run (Object [] Fuentes, String [] String) {return New SpringApplication (fuentes) .run (args); }Aquí la instancia de SpringApplication es la clave, vamos al constructor de SpringApplication.
/*** Crear una nueva instancia {@link SpringApplication}. El contexto de la aplicación se cargará * frijoles de las fuentes especificadas (consulte {@link SpringApplication Clase Level} * Documentación para obtener detalles. La instancia se puede personalizar antes de llamar * {@link #run (String ...)}. * @Param Fuente de las fuentes de bean * @see #run (objeto, string, []) * @see #SpringApaplation (recursos de recursos, objeto ...) */ public spring (object) */ public Spring (Object ... {Inicializar (fuentes); ApplicationContextInitialize.Class));Deducewebenvironment () en el método de inicializar aquí determina si se inicia actualmente con una aplicación web o un jar normal, de la siguiente manera:
privado booleano deducewebenvironment () {for (string classname: web_environment_classes) {if (! classUtil.esPresent (classname, null)) {return false; }} return verdadero; }Web_environment_classes es:
Cadena final estática privada [] web_environment_classes = {"javax.servlet.servlet", "org.springframework.web.context.configurablewebapplicationContext"};Mientras cualquiera de ellos no exista, la aplicación actual se inicia en forma de un frasco normal.
Luego, el método SetInitializers inicializa todos los AplicationContexTinitializers,
/** * Establece el {@link ApplicationContextInitializer} que se aplicará al resorte * {@link ApplicationContext}. * @param Inicializadores Los inicializadores para establecer */ public void setInitializers (Collection <? Extends ApplicationContextInitializer <? >> Inicializadores) {this.initializers = new ArrayList <ApplicationContextInitializer <?>> (); this.initializers.addall (inicializadores); } setListeners ((colección) GetSpringFactoriesInstances (ApplicationListener.class)) **Este paso inicializa a todos los oyentes.
Volvamos a la aplicación SpringArt (fuentes) anterior (args); e ingrese el método de ejecución, el código es el siguiente:
/** * Ejecute la aplicación Spring, creando y actualizando un nuevo * {@link ApplicationContext}. * @param argumenta los argumentos de la aplicación (generalmente pasados por un método principal de Java) * @return A en ejecución {@link ApplicationContext} */ public ConfiguableApplicationContext run (String ... args) {stopwatch stopwatch = new stopWatch (); stopwatch.start (); ConfiguableApplicationContext context = null; configureheadlessproperty (); SpringApplicationRunlisteners oyentes = GetRunListeners (args); oyentes. Pruebe {ApplicationArGuments ApplicationArGuments = new DefaultApplicationAarGuments (args); context = createAnDRefreshContext (oyentes, ApplicationArGuments); 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, ex); tirar nueva IllegalStateException (EX); }}Este paso realiza la creación de contexto CreateAndRefreshContext (oyentes, ApplicationArGuments),
Private ConfigurableApplicationContext CreateAnDreFreshContext (SpringApplicationRunListeners oyentes, ApplicationArGuments ApplicationArGuments) {ContextureableApplicationContext context; // Crear y configurar el entorno Configurable ENLOMENTALMENTOMENTO = GetOrCreateenVironment (); configureenvironment (entorno, applicationArGuments.getSourCeargs ()); oyentes. EnvironmentPrepared (entorno); if (isWebenVironment (ambiente) &&! this.webenvironment) {ambiente = convertTostandardenVironment (ambiente); } if (this.bannermode! = banner.mode.off) {printbanner (entorno); } // Crear, cargar, actualizar y ejecutar el context de ApplicationContext = CreateApplicationContext (); context.setenvironment (entorno); PostProcessApplicationContext (contexto); Aplicarinicializadores (contexto); oyentes.ContextPrepared (contexto); if (this.logstartupinfo) {logstartupinfo (context.getParent () == null); logstartUpprofileInfo (contexto); } // Agregar boot singleton frijoles context.getBeanFactory (). RegisterSingLeton ("SpringApplicationArGuments", ApplicationArGuments); // Cargue las fuentes establecidas <ject> fuentes = getSources (); Afirmar.notempty (fuentes, "Las fuentes no deben estar vacías"); load (context, fuentes.toarray (nuevo objeto [fuentes.size ()])); oyentes.ContextLoaded (contexto); // Actualizar la actualización del contexto (contexto); if (this.RegisterShutdownHook) {try {context.RegisterShutdownHook (); } Catch (AccessControlException ex) {// no está permitido en algunos entornos. }} Contexto de retorno; } // Crear y configurar el entorno Configurable ENLOMENTONMITORIO DELMITRO = GetOrCreateEnvironment (); configureenvironment (entorno, applicationArGuments.getSourCeargs ());Este paso lleva a cabo la configuración y la carga del entorno.
if (this.bannermode! = banner.mode.off) {printbanner (entorno); }Este paso imprime el logotipo de Spring Boot. Si necesita cambiarlo, agregue banner.txt y banner.txt al archivo de recursos para cambiarlo al patrón que necesita.
// Crear, cargar, actualizar y ejecutar el context de ApplicationContext = CreateApplicationContext (); return (configurureApplicationContext) beanutil.instantiate (contextclass)
El contexto de creación realmente incluye qué contenedor se crea e instancias de la clase de respuesta, incluida la creación de InbeddedServletContainerFactory, ya sea para elegir Jetty o Tomcat, hay mucho contenido, por lo que hablaré sobre eso la próxima vez.
if (this.RegisterShutdownHook) {try {context.RegisterShutdownHook (); } Catch (AccessControlException ex) {// no está permitido en algunos entornos. }}Este paso es registrar el contexto actual y destruir el contenedor cuando se recibe el comando Kill.
Básicamente, el análisis de inicio ha terminado, pero todavía hay algunos detalles que requieren mucho tiempo para contar. Esto se discutirá en la publicación de blog posterior, y eso es todo para hoy.
En resumen, el proceso de inicio de la jarra de arranque de Spring es básicamente los siguientes pasos:
1. Cuando empaquetamos Maven Normalmente, el complemento de arranque de Spring expande el ciclo de vida de Maven e imparte el paquete relacionado con el arranque de Spring en el frasco. Este JAR contiene archivos de clase relacionados con el programa Spring Boot Startup además de los frascos producidos por la aplicación.
2. He visto el proceso de inicio de una versión ligeramente más baja de Spring Boot Jar antes. En ese momento, recuerdo que el hilo actual tiene un nuevo hilo para ejecutar el programa principal, y ahora se ha cambiado para usar directamente la reflexión para iniciar el programa principal.
Resumir
Lo anterior es el análisis del principio de Spring Boot Jar introducido por el editor. Espero que te sea útil. Si tiene alguna pregunta, déjame un mensaje y el editor le responderá a tiempo. ¡Muchas gracias por su apoyo al sitio web de Wulin.com!