Prefacio
Este artículo analiza el principio de trabajo de Spring Boot 1.3. Boot de primavera 1.4. Después de eso, se descubrió que la estructura de empaque cambia y se agregó el directorio de Boot-INF, pero el principio básico permanece sin cambios.
Para los cambios en el cargador de clases en Spring Boot 1.4.*, Consulte: http://www.vevb.com/article/141479.htm
Spring Boot Inicio rápido
En Spring Boot, una característica muy atractiva es que la aplicación se puede empaquetar directamente en un jar/guerra, y luego este jar/guerra se puede iniciar directamente sin configurar otro servidor web.
Si no ha utilizado el arranque de primavera antes, puede experimentarlo a través de la demostración a continuación.
Aquí hay un proyecto como ejemplo para demostrar cómo comenzar el proyecto Spring Boot:
Git clon [email protected]: hengyunabc/spring-boot-demo.gitmvn spring-boot-demoJava -jar Target/Demo-0.0.1-snapshot.jar
Si el IDE utilizado es Spring STS o Idea, puede crear un proyecto de arranque de primavera a través del asistente.
También puede consultar el tutorial oficial:
http://docs.spring.io/spring-boot/docs/current-snapshot/reference/htmlsingingle/#getting-started-first-application
Dos preguntas sobre la bota de primavera
Cuando comienza a comunicarse con Spring Boot, generalmente tiene estas preguntas
Analicemos cómo se realiza el arranque de primavera.
Cómo se inicia la bota de primavera cuando se empaqueta como un solo frasco
Después de que Maven esté empaquetado, se generarán dos archivos JAR:
demo-0.0.1-snapshot.jardemo-0.0.1-snapshot.jar.original
donde demo-0.0.1-snapshot.jar.original es el paquete generado por Maven-Jar-Plugin predeterminado.
Demo-0.0.1-snapshot.jar es un paquete JAR generado por el complemento Spring Boot Maven, que contiene dependencias de aplicaciones y clases relacionadas con el arranque de primavera. En adelante, se llama Jar Jar.
Primero, verifiquemos la estructura del directorio de los paquetes preparados por Spring Boot (omitirlo si no es importante):
├── Meta-Inf│ ├── Manifest.Mf├── Aplicación. Properties├── Com│ └── Ejemplo └ └─omo SpringBootDemoApplication.Classs├─ Lib│ ├ ├ ─ aOpalliance-1.0.JAR│ ├ ─ Spring-Beans-4.2.3.Release.JAR│ ├ ├ ├ ├ ├ ├ ├ ├ ├ ├ ├ ├. Boot └── cargador ├── EjecutiveRearchligligaleMuncher.Class ├── jarlauncher.class ├── javaagentdetector.class ├── lanzadorclassclassloader.class ├── Lanzador.class ├─ija MainMethodrunner.class ├─ ├─ ...
Echemos un vistazo a estos contenidos a su vez.
Manifest.mf
Manifest-Version: 1.0Start-Class: com.example.springbootdemoApplicationImplementation-Vendor-id: com.examplespring-boot-version: 1.3.0.releaseAcreated-by: Apache Maven 3.3.3Build-JDK: 1.8.0_60IMPLIMENTACIÓN-VENDOR: PABE org.springframework.boot.loader.jarlauncher
Puede ver que la clase principal es org.springframework.boot.loader.jarlauncher, que es la función principal iniciada por JAR.
También hay una clase de inicio que es com.example.springbootdemoapplication, que es la función principal que aplicamos.
@SpringBootApplicationPublic Class SpringBootDemoApplication {public static void main (string [] args) {springapplication.run (springbootdemoapplication.class, args); }} directorio com/ejemplo
Aquí está el archivo .class de la aplicación.
directorio de lib
Aquí está el archivo del paquete JAR en el que depende de la aplicación.
Por ejemplo, primavera, primavera-MVC y otros frascos.
Org/SpringFramework/Boot/Loader Directory
Aquí está el archivo .class del cargador de arranque de Spring.
Concepto de archivo
En Spring Boot, el concepto de archivo se abstrae.
Un archivo puede ser un jar (jarFiLearchive) o un directorio de archivos (explosedarchive). Se puede entender como la capa de recursos de acceso unificado abstraído por Spring Boot.
El Demo-0.0.1-snapshot.jar anterior es un archivo, y luego cada paquete JAR bajo el directorio /lib en Demo-0.0.1-Snapshot.jar también es un archivo.
Public Abstract Class Archive {URL de abstracto público public GetUrl (); cadena pública getMainClass (); colección pública de resúmenes <ing entry> getEntries (); Lista de resúmenes públicos <Achive> getNesteredArchives (Filtro EntryFilter);Puedes ver que el archivo tiene su propia URL, como:
jar: archivo: /tmp/target/demo-0.0.1-snapshot.jar!/
También hay una función GetNesteredArchives, que en realidad devuelve la lista de archivos de frascos bajo Demo-0.0.1-snapshot.jar/lib. Sus URL son:
jar: archivo: /tmp/target/demo-0.0.1-snapshot.jar! /lib/aopalliance-1.0.jarjar: file: /tmp/target/demo-0.0.1-snapshot.jar! /Lib/spring-beans-4.2.3.release.jar
Jarlauncher
De Manifest.mf, podemos ver que la función principal es Jarlauncher. Analicemos su flujo de trabajo a continuación.
La estructura de herencia de la clase Jarlauncher es:
La clase Jarlauncher extiende EjecutiveCearchIleCleuncherClass EjecutivoCearchIlauncher Extends Launcher
Crea un archivo con Demo-0.0.1-Snapshot.jar:
Jarlauncher primero encuentra el camino del frasco donde se encuentra, es decir, demo-0.0.1-snapshot.jar, y luego crea un archivo.
El siguiente código muestra el truco de cómo encontrar la ubicación de carga desde una clase:
Archivo final protegido createARCHIVE () arroja excepción {ProtectionDomain ProtectionDomain = getClass (). GetProtectionDomain (); CodeSource CodeSource = ProtectionDomain.getCodeSource (); Uri ubicación = (CodeSource == NULL? NULL: CodeSource.getLocation (). Touri ()); String ruta = (ubicación == null? Null: ubicación.getSchemesPecificPart ()); if (Path == NULL) {Throw New IlegalStateException ("No se puede determinar el archivo de fuente de código"); } Archivo root = nuevo archivo (ruta); if (? } return (root.isDirectory ()? New Explodedarchive (root): new JarFiLearchive (root));} Obtenga el frasco debajo de Lib/ y cree un LockedUrlClassLoader
Después de que Jarlauncher crea Archive, usa la función GetNestedarchives para obtener todos los archivos JAR por debajo de Demo-0.0.1-Snapshot.jar/lib y los crea como lista.
Tenga en cuenta que, como se mencionó anteriormente, Archive tiene su propia URL.
Después de obtener estas URL de archivo, obtendrá una matriz de URL [] y lo usará para construir un cargador de clases personalizado: la elunchedUrlClassLoader.
Después de crear el cargador de clases, lea la clase de inicio de Manifest.mf, es decir, com.example.springbootdemoapplication, y luego cree un nuevo hilo para iniciar la función principal de la aplicación.
/*** Inicie la aplicación dado el archivo de archivo y un cargador de clases totalmente configurado. */Protected void Lunch (String [] args, String MainClass, ClassLoader ClassLoader) arroja excepción {runnable runner = createMeNMethodrunner (mainClass, args, classloader); Thread RunnerThread = New Thread (Runner); RunnerThread.SetContextClassLoader (classLoader); RunnerThread.SetName (Thread.CurrentThread (). getName ()); RunnerThread.start ();}/*** Crear el {@code mainmethodrunner} utilizado para iniciar la aplicación. */Protected Runnable CreateMainMethodrunner (String MainClass, String [] Args, ClassLoader ClassLoader) lanza la excepción {class <?> RunnerClass = ClassLoader.LoadClass (Runner_Class); Constructor <?> constructor = runnerClass.getConstructor (string.class, string []. Class); return (runnable) constructor.newinstance (mainclass, args);} LOWEREDURLCLASSLOGADER
La diferencia entre la elicada delgente de lanzamiento y la carga ordinaria URLClassLoader es que proporciona la capacidad de cargar. Clase desde el archivo.
Combinando la función Getentries proporcionada por Archive, puede obtener el recurso en Archive. Por supuesto, todavía hay muchos detalles en el interior, por lo que lo describiré a continuación.
Resumen del proceso de inicio de la aplicación de arranque de primavera
Después de ver esto, puede resumir el proceso de inicio de la aplicación Spring Boot:
Detalles en el cargador de arranque de primavera
Dirección del código: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-tools/spring-boot-loader
Extensiones de URL de jarfile
La bota de primavera se puede iniciar con un frasco gordo. Lo más importante es que implementa el método de carga de JAR en JAR.
La definición de la URL Jarfile original de JDK se puede encontrar aquí:
http://docs.oracle.com/javase/7/docs/api/java/net/jarurlconnection.html
La URL de Jarfile original se ve así:
jar: archivo: /tmp/target/demo-0.0.1-snapshot.jar!/
URL de recursos en el paquete JAR:
Copie el código de la siguiente manera: jar: archivo: /tmp/target/demo-0.0.1-snapshot.jar! /Com/example/springbootdemoapplication.class
Puede ver que para los recursos en JAR, la definición está separada por '!/'. La URL Jarfile original solo es compatible con uno '!/'.
Spring Boot extiende este protocolo para admitir múltiples '!/', Que puede representar JAR en JAR, JAR en recursos de directorio.
Por ejemplo, la siguiente URL representa la primavera-beans-4.2.3.release.jar en el directorio lib de demo-0.0.1-snapshot.jar:
Copie el código de la siguiente manera: jar: archivo: /tmp/target/demo-0.0.1-snapshot.jar! /Lib/spring-beans-4.2.3.release.jar! /Meta-inf/manifest.mf
URLStreamHandler personalizado, extender Jarfile y JarurlConnection
Al construir una URL, puede pasar un controlador y el JDK viene con una clase de controlador predeterminada. La aplicación puede registrar el controlador en sí para manejar URL personalizados.
URL pública (protocolo de cadena, host de cadena, puerto int, archivo de cadena, manejador urlstreamhandler) lanza malformedurexception
referirse a:
https://docs.oracle.com/javase/8/docs/api/java/net/url.html#url-java.lang.string-java.lang.string-int-java.lang.string-
Spring Boot maneja la lógica de múltiples frascos en frascos registrando una clase de controlador personalizado.
Este controlador usará Softreference para caché de jarfiles abiertos.
Al procesar URL como las siguientes, el separador '!/' Se procesa en bicicleta. Comenzando desde la capa superior, primero construya el Jarfile Demo-0.0.1-Snapshot.jar, luego construya el jarfile spring-beans-4.2.3.elease.jar, y luego construya la conexión jarurling apuntando a manifest.mf.
Copie el código de la siguiente manera: jar: archivo: /tmp/target/demo-0.0.1-snapshot.jar! /Lib/spring-beans-4.2.3.release.jar! /Meta-inf/manifest.mf
//org.springframework.boot.loader.jar.handlerpublic class Handler extiende urlstreamhandler {private static final string separator = "!/"; Softreference estático privado <map <file, jarfile >> rootFileCache; @Override urlconnection openconnection (url url) lanza ioexception {if (this.jarfile! = Null) {return new JarurlConnection (url, this.jarfile); } try {return new JarurlConnection (url, getrootjarfilefromurl (url)); } capt (excepción ex) {return OpenfallBackConnection (url, ex); }} public jarfile getRootJarFileFromUrl (url url) lanza ioexception {string spec = url.getFile (); int separatorIndex = spec.IndexOf (separador); if (separatorIndex == -1) {lanzar nueva malformedurexception ("jar url no contiene!/ separador"); } Name de cadena = spec.substring (0, separatorIndex); return getRootJarfile (nombre); } Cómo la clase Loader lee a los recursos
¿Qué habilidades requiere para un cargador de clases?
La API correspondiente es:
Public URL FindResource (nombre de cadena) Public InputStream GetResourceASStream (nombre de cadena)
Como se mencionó anteriormente, cuando el arranque de primavera construye el lanzamiento de ClassClassLoader, pasa una matriz de URL []. La matriz es la URL del frasco debajo del directorio LIB.
¿Cómo saben JDK o ClassLoader cómo leer el contenido para una URL?
De hecho, el proceso se ve así:
La llamada final es la función getInputStream () de JarurlConnection.
//org.springframework.boot.loader.jar.jarurlconnection @Override public titream getInputStream () lanza IOException {Connect (); if (this.JarEntryName.isEmpty ()) {lanzar nueva IOException ("sin nombre de entrada especificado"); } return this.jarEntryData.getInputStream (); }Desde una URL hasta leer finalmente el contenido en la URL, todo el proceso es bastante complicado. Resumamos:
Aquí hay muchos detalles, solo se enumeran algunos puntos importantes.
Entonces, ¿cómo se getResource UrlClassLoader?
Al construir el UrlClassLoader, tiene parámetros de matriz de URL [], y usará esta matriz para construir un URLClassPath:
URLClassPath ucp = nuevo URLClassPath (URLS);
En la URLClassPath, se construirá un cargador para todas las URL, y luego, al obtener el resumen, intentará obtenerlos de estos cargadores uno por uno.
Si la adquisición es exitosa, se empaqueta como un recurso como a continuación.
Recursos getResource (nombre final de cadena, cheque booleano) {URL final de URL; intente {url = new url (base, parseutil.encodepath (nombre, falso)); } catch (malformedurexception e) {tirar nueva ilegalargumentException ("nombre"); } Final URLConnection uc; intente {if (check) {urlClassPath.eckek (url); } UC = url.openconnection (); InputStream in = uc.getInputStream (); if (UC InstanceOf JarurlConnection) { / * Debe recordar el archivo JAR para que pueda cerrarse * a toda prisa. */ Jarurlconnection juc = (jarurlconnection) uc; jarfile = jarloader.checkjar (juc.getjarfile ()); }} capt (excepción e) {return null; } return new Resource () {public String getName () {return name; } public url getUrl () {URL de retorno; } public url getCodeSourceUrl () {Base de retorno; } public inputStream getInputStream () lanza ioexception {return uc.getInputStream (); } public int getContentLength () lanza ioexception {return uc.getContentLength (); }};}Como puede ver en el código, URL.openconnection () en realidad se llama. De esta manera, la cadena completa se puede conectar.
Tenga en cuenta que el código de la clase UrlClassPath no viene con el suyo en el JDK. Aquí puede ver http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/misc/urlclasspath.java#506
Iniciar la aplicación Boot Spring en el directorio IDE/Open
Lo anterior solo se menciona el proceso de inicio de la aplicación de arranque de primavera en un frasco de grasa. El siguiente es un análisis de cómo se inicia el arranque de primavera en el IDE.
En el IDE, la función principal que se ejecuta directamente es aplicar su propia función principal:
@SpringBootApplicationPublic Class SpringBootDemoApplication {public static void main (string [] args) {springapplication.run (springbootdemoapplication.class, args); }}De hecho, la aplicación de arranque de primavera inicial en el IDE es el caso más fácil, porque los frascos de dependencia se colocan en el classpath, por lo que el arranque de primavera acaba de comenzar.
Otra situación es comenzar el arranque de primavera en un directorio abierto. El llamado directorio abierto es descomprimir el frasco de grasa y luego comenzar directamente la aplicación.
Java org.springframework.boot.loader.jarlauncher
En este momento, Spring Boot determinará si se encuentra actualmente en un directorio. Si es así, construya un explosivo (el anterior es JarFiLearchive), y el proceso de inicio posterior es similar al Jar de grasa.
Proceso de inicio de Embead Tomcat
Determinar si se encuentra en el entorno web
Cuando se inicia el arranque de la primavera, primero determine si se encuentra en el entorno web simplemente buscando en la clase Servlet:
cadena final estática privada [] web_environment_classes = {"javax.servlet.servlet", "org.springframework.web.context.configurablewebapplicationContext"}; private boolean deducewebenvironment () {para (string className: web_environment_classes) {si (! ClassUtils.esPresent (classname, null)) {return false; }} return true;}Si es así, se creará AnnotationConfigembedDedWebApplicationContext, de lo contrario, el contexto de primavera es AnnotationConfigApplicationContext:
//org.springframework.boot.springapplication protegido ConfigureableApplicationContext CreateApplicationContext () {class <?> ContextClass = this.AplicationContextCass; if (contextclass == null) {try {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); } Obtenga la clase de implementación de InbeddedServletContainerFactory
Spring Boot comienza el servidor web correspondiente obteniendo InceddedServletContainerFactory.
Las dos clases de implementación comúnmente utilizadas son TomCatembeddedServletContainerFactory y JettyembeddedServletContainerFactory.
Código para iniciar Tomcat:
// TomCatembedDedServletContainerFactory@overRidePublic IncorpeddedServletContainer GetEmbedDedServletContainer (ServletContextInitializer ... Inicializadores) {Tomcat TomCat = new TomCat (); Archivo basado = (this.basedirectory! = Null? This.basedir: createTempDir ("TomCat")); TomCat.SetBasedir (BaseIR.GetAbSolutePath ()); Conector conector = nuevo conector (this.protocol); tomcat.getService (). addconnector (conector); CustomizeConnector (conector); TomCat.SetConnector (conector); tomcat.gethost (). setAutodePloy (falso); Tomcat.getEngine (). SegetbackgroundProcessordLay (-1); para (conector adicionalConnector: this.AdditionAltomCatConnectors) {tomcat.getService (). addconnector (adicionalConnector); } prepareContext (tomcat.gethost (), inicializadores); return getTomCatembedDedServletContainer (Tomcat);} Se creará un directorio de archivos temporal para TomCat, como:
/tmp/tomcat.2233614112516545210.8080, como la base de Tomcat. Los archivos temporales de Tomcat, como el directorio de trabajo, se colocarán dentro.
Algunos servlets de Tomcat también se inicializarán, como el valor predeterminado más importante/JSP: Servlet:
Private void addFaultServlet (contexto context) {wrapper defaultservlet = context.createwrapper (); defaultservlet.setName ("predeterminado"); defaultservlet.setservletclass ("org.apache.catalina.servlets.defaultServlet"); defaultservlet.addinitParameter ("debug", "0"); defaultservlet.addinitParameter ("listados", "falso"); defaultServlet.SetLoadOnStartUp (1); // de lo contrario, la ubicación predeterminada de un Spring DispatcherServlet no se puede establecer defaultservlet.setOverRidable (true); context.addchild (defaultServlet); context.addservletMapping ("/", "predeterminado");} private void addjspServlet (context context) {wrapper jspservlet = context.createwrapper (); jspservlet.setName ("jsp"); jspservlet.setservletClass (getJSpServletClassName ()); jspservlet.addinitParameter ("bifurcado", "falso"); JSPServlet.SetLoadOnStartUp (3); context.addchild (jspservlet); context.addservletMapping ("*. jsp", "jsp"); context.addservletMapping ("*. jspx", "jsp");} Cómo acceder a los recursos con la aplicación web Spring Boot
¿Cómo accedo al recurso web cuando la aplicación Spring Boot está empaquetada como un frasco gordo?
En realidad, se implementa a través de la URL proporcionada por Archive y luego a través de la capacidad de acceder al recurso ClassPath proporcionado por ClassLoader.
index.html
Por ejemplo, debe configurar un índice.html, que se puede colocar directamente en el directorio src/main/recursos/estático en el código.
Para la página de bienvenida index.html, cuando se inicializa Spring Boot, se creará un ViewController para manejar:
// ResourcePropertiesPublic Class ResourceProperties implementa ResourCelOaderaware {String final estático privado [] servlet_resource_locations = {"/"}; Cadena final estática privada [] classpath_resource_locations = {"classpath:/meta -inf/recursos/", "classpath:/recursos/", "classpath:/static/", "classpath:/public/"}; // WebMVCAUTOCONFigurationAdapter @Override public void addViewControllers (ViewControllerRegistry Registry) {Page de recursos = this.resourceProperties.getWelcomePage (); if (page! = null) {logger.info ("Agregar página de bienvenida:" + página); Registry.AddViewController ("/"). SetViewName ("Forward: index.html"); }} plantilla
Por ejemplo, el archivo de plantilla de página se puede colocar en el directorio src/main/recursos/plantilla. Pero esto en realidad es manejado por la clase de implementación de plantilla en sí. Por ejemplo, en la clase ThymeleafProperties:
public static final String default_prefix = "classpath:/plantlates/";
JSP
La página JSP es similar a la plantilla. En realidad, se maneja a través del JSTLVIEW incorporado en Spring MVC.
Puede configurar Spring.View.Prefix para establecer el directorio de la página JSP:
spring.view.prefix:/web-inf/jsp/
Manejo de páginas de error unificadas en el arranque de primavera
Para las páginas de error, Spring Boot también se maneja de manera uniforme creando un BasicErrorController.
@Controlador@requestmapping ("$ {server.error.path: $ {error.path:/error}}") public class BasicErrIrController extiende AbstracterRorControllerLa vista correspondiente es un simple recordatorio HTML:
@Configuration@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)@Conditional(ErrorTemplateMissingCondition.class)protected static class WhitelabelErrorViewConfiguration { private final SpelView defaultErrorView = new SpelView( "<html><body><h1>Whitelabel Error Page</h1>" + "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>" + "<div id='created'>${timestamp}</div>" + "<div>There was an unexpected error (type=${error}, status = $ {status}). </div> " +" <div> $ {mensaje} </div> </body> </html> "); @Bean (name = "Error") @ConditionAlonMissingBean (name = "Error") Vista pública DeFoulterRorView () {return this.defaulterRorView; }Spring Boot es una buena práctica, lo que evita la excepción predeterminada cuando las aplicaciones web tradicionales cometen errores, lo que facilita la fuga de secretos.
Proceso de embalaje maven de la aplicación de arranque de primavera
Primero, genere un fras que contenga dependencias a través de Maven-shade-plugin, y luego empaque las clases relacionadas con el cargador de arranque de Spring y manifiesto.
Implementación de registros de color en Spring Boot
Al comenzar la aplicación Spring Boot en el shell, encontrará que la salida de su registrador está coloreada, lo cual es muy interesante.
Esta configuración se puede apagar:
spring.output.ansi.enabled = falso
El principio es obtener esta configuración a través de ANSIOUTPUTApplicationListener, y luego establecer el registro para salir, agregar un ColorConverter y representar algunos campos a través de org.springframework.boot.ansi.ansioutput.
Algunos consejos de código
Al implementar classloader, admite la carga paralela JDK7
Puede consultar el LockProvider en la elunchedUrlClassLoader
Public Class LaunchedUrlClassLoader extiende URLClassLoader {private static LockProvider Lock_Provider = setUplockProvider (); Private static lockProvider setUpplockProvider () {try {classLoader.RegisterAsParallelCapable (); devolver nuevo Java7LockProvider (); } catch (nosuchmethoderror ex) {return new LockProvider (); }} @Override Clase protegida <?> LoadClass (nombre de cadena, Boolean Resolve) lanza ClassNotFoundException {SynChronized (LaunchedUrlClassLoader.lock_provider.getLock (this, name)) {class <?> LoadedClass = findLoteClass (name); if (loadedClass == null) {handler.setuseFastConnectionExCeptions (true); intente {loadedClass = doloadclass (nombre); } finalmente {handler.setUseFastConnectionExcepciones (falso); }} if (resolve) {resolveclass (LoadedClass); } return LoadedClass; }} Verifique si el paquete jar se carga a través del agente
InputArGumentsJavaagentDetector, el principio es detectar si la URL del frasco tiene el prefijo de "-javaagent:".
cadena final estática privada java_agent_prefix = "-javaagent:";
Obtenga el PID del proceso
ApplicationPid, puede obtener el PID.
Private String getpid () {try {String jvmname = gestorFactory.getRuntimemxBean (). getName (); return jvmname.split ("@") [0]; } Catch (Throwable Ex) {return null; }} Clase de registrador de embalaje
Spring Boot tiene un conjunto de registradores que admiten Java, Log4J, Log4J2, Logback. Puede consultar esto cuando necesite empaquetar sus registradores usted mismo en el futuro.
Bajo el paquete org.springframework.boot.logging.
Obtenga la función principal iniciada original
A través del método obtenido en la pila, juzgue la función principal y encuentre la función principal iniciada original.
clase privada <?> deducemainApplicationClass () {try {stackTraceElement [] stackTrace = new runtimeException (). getStackTrace (); para (StackTraceElement StackTraceElement: StackTrace) {if ("main" .equals (stackTraceElement.getMethodName ())) {return class.forname (stackTraceElement.getClassName ()); }}} Catch (ClassNotFoundException ex) {// Swallow y continúa} return null;} Algunas desventajas de Spirng Boot:
Cuando la aplicación de arranque de primavera se ejecuta en un frasco gordo, se encontrarán algunos problemas. Aquí están mis opiniones personales:
Resumir
Spring Boot extiende el protocolo JAR, abstrae el concepto de archivo y el soporte de jarfile, jarurlconnection y el lanzamiento deClassClassLoader, realizando así la experiencia de desarrollo de todos en uno sin percepción de la aplicación de la capa superior. Aunque la guerra ejecutable no es un concepto propuesto por la primavera, Spring Boot permite que se transfiera.
Spring Boot es un proyecto increíble, que se puede decir que es la segunda primavera de primavera. Spring-Cloud-Config, Spring-Session, Metrics, Remote Shell, etc. son todos los proyectos y características que los desarrolladores aman. Es casi seguro que el diseñador tiene una rica experiencia en el desarrollo de primera línea y es consciente de los puntos débiles de los desarrolladores.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.