Préface
Cet article analyse le principe de travail de Spring Boot 1.3. Spring Boot 1.4. Après cela, la structure d'emballage a été constatée et le répertoire de démarrage a été ajouté, mais le principe de base reste inchangé.
Pour les modifications de Classloader dans Spring Boot 1.4. *, Veuillez vous référer à: http://www.vevb.com/article/141479.htm
démarrage rapide du démarrage de printemps
Dans Spring Boot, une fonctionnalité très attrayante est que l'application peut être emballée directement dans un pot / guerre, puis ce pot / guerre peut être démarré directement sans configurer un autre serveur Web.
Si vous n'avez pas utilisé Spring Boot auparavant, vous pouvez en faire l'expérience à travers la démo ci-dessous.
Voici un projet comme exemple pour montrer comment démarrer le projet Spring Boot:
git clone [email protected]: Hengyunabc / printemps-boot-temo.gitmvn printemps-boot-demojava -jar cible / Demo-0.0.1-snapshot.jar
Si l'IDE utilisé est Spring STS ou IDEA, vous pouvez créer un projet de démarrage de printemps via l'assistant.
Vous pouvez également vous référer au tutoriel officiel:
http://docs.spring.io/spring-boot/docs/current-snapshot/reference/htmlsingle/#getting-started-first-application
Deux questions sur Spring Boot
Lorsque vous commencez à contacter Spring Boot, vous avez généralement ces questions
Analyons comment Spring Boot est terminé.
Comment le démarrage du printemps est démarré lorsqu'il est emballé comme un seul pot
Une fois Maven emballé, deux fichiers en pot seront générés:
Demo-0.0.1-Snapshot.Jardemo-0.0.1-Snapshot.jar.original
où Demo-0.0.1-Snapshot.jar.original est le package généré par Maven-Jar-Plugin par défaut.
Demo-0.0.1-Snapshot.jar est un package JAR généré par le plug-in Spring Boot Maven, qui contient des dépendances d'application et des classes liées au démarrage Spring. Ci-après, il s'appelle Fat Jar.
Tout d'abord, vérifions la structure du répertoire des packages préparés par Spring Boot (omettons-le s'il n'est pas important):
├fiquesla-inf│ ├fiquement. Boot └── Loder ├── ExecutiVechingIvelAncher.class ├── Jarlauncher.class ├── JavaAgentDetector.Class ├fiquee
Jetons un coup d'œil à ces contenus tour à tour.
Manifeste.mf
Version manifeste: 1.0Start-Class: com.example.springbootdemoapplicationIMPlementation-vendor-id: com.examplespring-boot-version: 1.3.0.releasecreed-by: Apache Maven 3.3.3Build-jdk: 1.8.0_60IMPLIMINATION-VENDOR: PIVOTAL SOFFLOKY, INC. org.springframework.boot.loader.jarlauncher
Vous pouvez voir que la classe principale est org.springframework.boot.loader.jarlauncher, qui est la fonction principale lancée par Jar.
Il existe également une classe de démarrage qui est com.example.springbootdemoapplication, qui est la fonction principale que nous appliquons.
@SpringBootApplicationPublic classe SpringbootDemoApplication {public static void main (String [] args) {SpringApplication.Run (SpringbootDemoApplication.class, Args); }} com / exemple répertoire
Voici le fichier .class de l'application.
répertoire lib
Voici le fichier de package JAR dont la demande dépend.
Par exemple, les haricots printaniers, le printemps-MVC et d'autres pots.
Répertoire org / springframework / boot / loder
Voici le fichier .class du chargeur de démarrage Spring.
Concept d'archive
Dans Spring Boot, le concept d'archive est abstrait.
Une archive peut être un pot (jarfilearchve) ou un répertoire de fichiers (ExplodEdArchive). Il peut être compris comme la couche de ressources d'accès unifiées abstraites par Spring Boot.
Le Demo-0.0.1-Snapshot.jar ci-dessus est une archive, puis chaque package JAR sous le répertoire / lib dans Demo-0.0.1-Snapshot.jar est également une archive.
Archive de classe abstraite publique {URL abstrait public getUrl (); public String getMainClass (); Collection abstraite publique <Spery> getEntries (); Liste abstraite publique <Carchive> GetNestedArchives (filtre Entrée);Vous pouvez voir que Archive a sa propre URL, comme:
jar: fichier: /tmp/target/demo-0.0.1-snapshot.jar! /
Il existe également une fonction GetSestedArchives, qui renvoie en fait la liste des archives des pots sous Demo-0.0.1-Snapshot.jar / lib. Leurs URL sont:
JAR: fichier: /tmp/target/demo-0.0.1-snapshot.jar! /lib/aopalliance-1.0.jarjar: fichier: /tmp/target/demo-0.0.1-snapshot.jar! /lib/spring-beans-4.2.3.release.jar!
Jarlauncher
De Manifest.MF, nous pouvons voir que la fonction principale est Jarlauncher. Analysons son flux de travail ci-dessous.
La structure d'héritage de la classe Jarlauncher est:
Class Jarlauncher étend ExecutiVearchIlAlAnCherclass ExecutiveAclAlAlauncher étend le lanceur
Créez une archive avec Demo-0.0.1-Snapshot.jar:
Jarlauncher trouve d'abord le chemin du pot où il est situé, c'est-à-dire Demo-0.0.1-Snapshot.jar, puis crée une archive.
Le code suivant montre l'astuce de la façon de trouver l'emplacement de chargement d'une classe:
Archive final protégé Crearcandve () lève une exception {ProtectionDomAiN ProtectionDomain = getClass (). getProtectionDomain (); Codesource codesource = protectionDom.getCoDesource (); URI Location = (codesource == null? Null: codesource.getLocation (). TOURI ()); String path = (location == null? Null: location.getschemeSpecificPart ()); if (path == null) {lancez new illégalStateException ("Impossible de déterminer les archives de la source de code"); } Fichier root = nouveau fichier (chemin); if (! root.exists ()) {Throw New illégalStateException ("Impossible de déterminer l'archive de la source de code de" + root); } return (root.isDirectory ()? New ExplodEdarchive (root): new JarFileChearve (root));} Obtenez le pot en dessous de lib / et créez un lancé
Après que Jarlauncher ait créé des archives, il utilise la fonction Getnestarchives pour obtenir tous les fichiers JAR ci-dessous Demo-0.0.1-Snapshot.jar / lib et les crée comme liste.
Notez que, comme mentionné ci-dessus, Archive a sa propre URL.
Après avoir obtenu ces URL d'archives, vous obtiendrez un tableau URL [] et l'utiliserez pour construire un Classloader personnalisé: LaunsedUrlClassloader.
Après avoir créé le classloader, lisez la classe start à partir de manifeste.mf, c'est-à-dire com.example.springbootdemoapplication, puis créez un nouveau thread pour démarrer la fonction principale de l'application.
/ ** * Lancez l'application compte tenu du fichier d'archive et d'un classloader entièrement configuré. * / Protected void Launch (String [] args, String MainClass, classloader classloader) lève l'exception {runnable runner = CreateMainMethoDrunner (mainclass, args, classloader); Thread Runnerthread = nouveau thread (coureur); RunnerThread.setContextClassloader (classloader); RunnerThread.SetName (Thread.currentThread (). getName ()); RunnerThread.Start ();} / ** * Créez le {@code MainMethodRunner} utilisé pour lancer l'application. * / Protection Runnable CreateMainMethoDrunner (String MainClass, String [] Args, classloader classloader) lève exception {class <?> RunnerClass = classloader.loadClass (runner_class); Constructor <?> Constructor = RunnerClass.getConstructor (String.class, String []. Class); return (runnable) constructor.newinstance (mainclass, args);} Lancé
La différence entre LaunchEdUrlClassLoader et UrlClassLoader ordinaire est qu'il offre la possibilité de charger .Class à partir d'archive.
En combinant la fonction GetEntries fournie par Archive, vous pouvez obtenir la ressource dans Archive. Bien sûr, il y a encore de nombreux détails à l'intérieur, donc je le décrirai ci-dessous.
Résumé du processus de démarrage de l'application Spring Boot
Après avoir vu cela, vous pouvez résumer le processus de démarrage de l'application Spring Boot:
Détails dans Spring Boot Loader
Adresse du code: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-tools/spring-boot-loadier
Extensions des URL de Jarfile
Spring Boot peut être démarré avec un gros pot. La chose la plus importante est qu'il met en œuvre la méthode de chargement du pot dans JAR.
La définition de l'URL de Jarfile d'origine de JDK peut être trouvée ici:
http://docs.oracle.com/javase/7/docs/api/java/net/jarurlconnection.html
L'URL Jarfile d'origine ressemble à ceci:
jar: fichier: /tmp/target/demo-0.0.1-snapshot.jar! /
URL de ressource dans le package JAR:
Copiez le code comme suit: jar: fichier: /tmp/target/demo-0.0.1-snapshot.jar! /Com/example/springbootdemoapplication.class
Vous pouvez voir que pour les ressources en pot, la définition est séparée par '! /'. L'URL Jarfile d'origine ne supporte qu'un '! /'.
Spring Boot étend ce protocole pour prendre en charge plusieurs '! /', Qui peut représenter JAR dans Jar, Jar dans les ressources de répertoire.
Par exemple, l'URL suivante représente le Spring-Beans-4.2.3.release.jar dans le répertoire Lib de Demo-0.0.1-Snapshot.jar:
Copiez le code comme suit: Jar: fichier: /tmp/target/demo-0.0.1-snapshot.jar! /Lib/spring-beans-4.2.3.release.jar! /Meta-inf/manifest.mf
UrlstreamHandler personnalisé, étendre Jarfile et JarurlConnection
Lors de la construction d'une URL, vous pouvez passer un gestionnaire et le JDK est livré avec une classe de gestionnaire par défaut. L'application peut enregistrer le gestionnaire lui-même pour gérer les URL personnalisées.
URL publique (protocole de chaîne, hôte de chaîne, port int, fichier de chaîne, gestionnaire UrlStreamHandler) lève la conception malformedUrException
se référer à:
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 gère la logique de plusieurs pots dans des bocaux en enregistrant une classe de gestionnaire personnalisée.
Ce gestionnaire utilisera Softreference pour mettre en cache tous les jarfiles ouverts.
Lors du traitement des URL comme les suivants, le séparateur '! /' Est traité à cycle. À partir de la couche supérieure, construisez d'abord le JarFile Demo-0.0.1-Snapshot.jar, puis construisez les barines de ressort de Jarfile-4.2.3.release.jar, puis construisez le jarurlconnection pointant vers manifeste.mf.
Copiez le code comme suit: Jar: fichier: /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 Handler étend UrlStreamHandler {private static final string séparateur = "! /"; Softreference statique privée <map <file, jarfile >> rootFileCache; @Override Protected URLConnection OpenConnection (URL URL) lève ioException {if (this.jarfile! = Null) {return new JarurlConnection (url, this.jarfile); } essayez {return new JarurlConnection (url, getrootjarfileFromurl (url)); } catch (exception ex) {return openfallbackConnection (url, ex); }} public jarfile getrootjarfilefromurl (url url) lève ioException {string spec = url.getFile (); int séparateurIndex = spec.Indexof (séparateur); if (séparatorIndex == -1) {Throw new MalformEdUrlexception ("URL JAR ne contient pas! / Séparateur"); } String name = spec.SubString (0, séparateurIndex); return getrootjarfile (nom); } Comment Classloader se lit sur les ressources
Quelles capacités nécessite-t-elle pour un chargeur de classe?
L'API correspondante est:
URL publique FindResource (nom de chaîne) public EntruStream GetResourceSstream (nom de chaîne)
Comme mentionné ci-dessus, lorsque Spring Boot Constructs a lancédUrlClassloadher, il passe un tableau URL []. Le tableau est l'URL du pot sous le répertoire Lib.
Comment JDK ou Classloader sait-il comment lire le contenu pour une URL?
En fait, le processus ressemble à ceci:
L'appel final est la fonction getInputStream () de JarurlConnection.
//org.springframework.boot.loader.jar.jarurlconnection @Override public inputStream getInputStream () lève ioException {connect (); if (this.jarentryname.isempty ()) {throw new ioException ("aucun nom d'entrée spécifié"); } return this.jarentrydata.getInputStream (); }D'une URL à la lecture enfin du contenu dans l'URL, l'ensemble du processus est assez compliqué. Résumons:
Il y a beaucoup de détails ici, seuls certains points importants sont répertoriés.
Ensuite, comment UrlClassloader GetResource?
Lors de la construction de l'URLClassloadher, il a des paramètres de tableau URL [] et il utilisera ce tableau pour construire un UrlClassPath:
UrlClassPath UCP = new UrlClassPath (URLS);
Dans l'URLClassPath, un chargeur sera construit pour toutes les URL, puis lors de l'obtention de Resource, il essaiera de les obtenir de ces chargeurs un par un.
Si l'acquisition est réussie, elle est emballée comme une ressource comme ci-dessous.
Resource getResource (nom de chaîne finale, booléen chèque) {URL final URL; try {url = new URL (base, paseutil.encodepath (name, false)); } catch (malformEdUrlexception e) {lancer un nouveau illégalArgumentException ("nom"); } URLConnection finale UC; essayez {if (check) {urlclasspath.check (url); } uc = url.openconnection (); InputStream dans = uc.getInputStream (); if (uc instanceof jarurlconnection) {/ * doit se souvenir du fichier jar afin qu'il puisse être fermé * à la hâte. * / JarurlConnection Juc = (JarurlConnection) UC; jarfile = jarloader.checkjar (juc.getjarfile ()); }} catch (exception e) {return null; } return new Resource () {public String getName () {return name; } public url getUrl () {return url; } URL publique getcodesourceUrl () {return base; } public inputStream getInputStream () lève ioException {return uc.getInputStream (); } public int getContentLength () lève ioException {return uc.getContentLength (); }};}Comme vous pouvez le voir dans le code, URL.OpenConnection () est réellement appelé. De cette façon, la chaîne complète peut être connectée.
Notez que le code de la classe UrlClassPath ne vient pas avec le sien dans le JDK. Ici, vous pouvez voir http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/misc/urlclasspath.java#506
Démarrer l'application Spring Boot dans IDE / Open Directory
Ce qui précède n'est mentionné que le processus de démarrage de l'application Spring Boot dans un gros pot. Ce qui suit est une analyse de la façon dont Spring Boot est démarré dans l'IDE.
Dans l'IDE, la fonction principale qui est directement exécutée est d'appliquer sa propre fonction principale:
@SpringBootApplicationPublic classe SpringbootDemoApplication {public static void main (String [] args) {SpringApplication.Run (SpringbootDemoApplication.class, Args); }}En fait, le démarrage de l'application Spring Boot dans l'IDE est le cas le plus simple, car les pots de dépendance sont placés dans le chemin de classe, donc Spring Boot vient de commencer.
Une autre situation consiste à démarrer Spring Boot dans un répertoire ouvert. Le soi-disant répertoire ouvert consiste à décompresser le JAR FAT, puis à démarrer directement l'application.
java org.springframework.boot.loader.jarlauncher
À l'heure actuelle, Spring Boot déterminera s'il est actuellement dans un répertoire. Dans l'affirmative, construisez un explosé en explosion (le précédent est jarfilarchve), et le processus de démarrage ultérieur est similaire à Fat Jar.
Processus de démarrage de Tomcat Embread
Déterminez s'il est dans l'environnement Web
Lorsque Spring Boot est démarré, déterminez d'abord s'il est dans l'environnement Web en recherchant simplement la classe de servlet:
String final statique privé [] web_environment_classes = {"javax.servlet.servlet", "org.springframework.web.context.configurablewebapplicationcontext"}; private boolean dedudusewenvironment () {for (string className: web_environment_classes) {if (if (krassutimes. null)) {return false; }} retourne true;}Si c'est le cas, AnnotationConfigeMedDedWebApplicationContext sera créée, sinon le contexte de printemps est AnnotationConfigApplicationContex:
//org.springframework.boot.springApplication Protected ConfigurableApplicationContext CreateApplicationContext () {class <?> contextClass = this.ApplicationContextClass; if (contextClass == null) {try {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); } Obtenez la classe d'implémentation de EmbedDeservletContainerFactory
Spring Boot démarre le serveur Web correspondant en obtenant EmbedDeDServletContainerFactory.
Les deux classes d'implémentation couramment utilisées sont TomCateMedDedServletContainerFactory et JettyEmbedDedServletContainerFactory.
Code pour démarrer Tomcat:
// tomcatembeddedServletContainerFactory @ Overdepublic EmbedDedServletContainer GetEmbedDedServletContainer (ServletContextInitializer ... initialisers) {tomcat tomcat = new tomcat (); File-Basedir = (this.basedirectory! = Null? This.basedir: createtempdir ("tomcat")); tomcat.setbasedir (basasedir.getAbsolutepath ()); Connecteur connecteur = nouveau connecteur (this.protocol); tomcat.getService (). addConnector (connecteur); PersonnaliseConnector (connecteur); tomcat.setConnector (connecteur); tomcat.gethost (). setAutodePloy (false); tomcat.getEngine (). SetbackgroundProcessordelay (-1); pour (connecteur supplémentaire Connector: this.AdditionalTomCatConnectors) {tomcat.getService (). AddConnector (AdditionalConnector); } prepareContext (tomcat.gethost (), initialiseurs); Retour GetTomCatembedDedServletContainer (Tomcat);} Un répertoire de fichiers temporaire sera créé pour Tomcat, tel que:
/tmp/tomcat.2233614112516545210.8080, comme base de Tomcat. Les fichiers Tomcat temporaires, tels que le répertoire de travail, seront placés à l'intérieur.
Certains servlets Tomcat seront également initialisés, comme le servlet par défaut / JSP le plus important:
private void addDefaultServlet (context context) {wrapper defaultServlet = context.CreatewRapper (); defaultServlet.SetName ("Default"); defaultServlet.SetServletClass ("org.apache.catalina.servlets.defaultServlet"); defaultServlet.addinitParameter ("Debug", "0"); defaultServlet.addinitParameter ("listes", "false"); defaultServlet.setLoadOnStartup (1); // Sinon, l'emplacement par défaut d'un Spring Dispatcherservlet ne peut pas être défini defaultServlet.SetOverridable (true); context.addchild (defaultServlet); context.AddServletMapping ("/", "Default");} private void addjSpservlet (context context) {wrapper jSpservlet = context.createwrapper (); jspservlet.setName ("jsp"); JSPServlet.SetServletClass (getJSPServletClassName ()); jspservlet.addinitaMeter ("Fork", "false"); jspservlet.setLoadOnStartup (3); context.addchild (jSpServlet); context.addServletMapping ("*. jsp", "jsp"); context.addServletMapping ("*. jspx", "jsp");} Comment accéder aux ressources avec l'application Web Spring Boot
Comment accéder à la ressource Web lorsque l'application Spring Boot est emballée sous forme de gros pot?
Il est en fait implémenté via l'URL fourni par Archive, puis par la possibilité d'accéder à la ressource ClassPath fournie par Classloader.
index.html
Par exemple, vous devez configurer un index.html, qui peut être placé directement dans le répertoire SRC / Main / Resources / Static dans le code.
Pour la page de bienvenue index.html, lorsque Spring Boot est initialisé, une ViewController sera créée pour gérer:
// ResourcePropertiesPublic Class ResourceProperties implémente ResourceLoaderaware {private static final String [] servlet_resource_locations = {"/"}; chaîne finale statique privée [] classpath_resource_locations = {"classpath: / meta-inf / ressources /", "classpath: / ressources /", "classpath: / static /", "classpath: / public /"}; // webmvcautoconfigurationadapter @Override public void addViewControllers (registre ViewControllerRegistry) {Resource Page = this.ResourceProperties.getWelcomePage (); if (page! = null) {logger.info ("Ajouter la page de bienvenue:" + page); registry.addViewController ("/"). setViewName ("Forward: index.html"); }} modèle
Par exemple, le fichier de modèle de page peut être placé dans le répertoire SRC / Main / Resources / Template. Mais cela est en fait géré par la classe d'implémentation de modèle elle-même. Par exemple, dans la classe des propriétés Thymeleaf.
public static final String default_prefix = "classpath: / templates /";
jsp
La page JSP est similaire au modèle. Il est en fait géré via le JSTLView construit dans le printemps MVC.
Vous pouvez configurer Spring.View.Prefix pour définir le répertoire de la page JSP:
printemps.view.prefix: / web-inf / jsp /
Gestion des pages d'erreur unifiées dans Spring Boot
Pour les pages d'erreur, Spring Boot est également géré uniformément en créant un BasicErrorController.
@ Contrôleur @ requestmapping ("$ {server.error.path: $ {error.path: / error}") classe publique BasicErrorController étend AbstracterrorControllerLa vue correspondante est un simple rappel HTML:
@ Configuration @ conditionalonProperty (prefix = "server.error.whiteLabel", name = "activé", matchIFMissing = true) @conditional (errorEmplatemissingCondition.class) Protected static static whiteLabelerorViewConfiguration {private final spelview defaulterRorView = new Spelview ("<html> <h11> Page d'erreur </h1> "+" <p> Cette application n'a pas de mappage explicite pour / erreur, vous voyez donc cela comme un replacement. </p> "+" <div id = 'créé'> $ {Timestamp} </div> "+" <div> Il y avait une erreur inattendue (type = $ {error}, status = $ {status}). </v> "+" + "<div> $ {message} </div> </ body> </html>"); @Bean (name = "error") @conditionalonMissingBean (name = "error") public View defaulterRorView () {return this.defaulterrorView; }Spring Boot est une bonne pratique, ce qui évite l'exception par défaut lancée lorsque les applications Web traditionnelles font des erreurs, ce qui facilite la fuite de secrets.
Processus d'emballage Maven de l'application Spring Boot
Tout d'abord, générez un pot contenant des dépendances via Maven-Shade-Plugin, puis emballez les classes liées au chargeur de démarrage Spring et à Manifest.MF dans le pot via le plugin Spring-Boot-Maven-Plugin.
Implémentation des journaux de couleur dans Spring Boot
Lors du démarrage de l'application Spring Boot dans le shell, vous constaterez que sa sortie d'enregistrement est colorée, ce qui est très intéressant.
Ce paramètre peut être désactivé:
printemps.output.ansi.enabled = false
Le principe est d'obtenir cette configuration via ANSIOutputApplicationListener, puis de définir la connexion sur la sortie, d'ajouter un ColorConverter et de rendre certains champs via org.springframework.boot.ansi.ansioutput.
Quelques conseils de code
Lors de l'implémentation de Classloader, prends en charge le chargement parallèle JDK7
Vous pouvez vous référer au LockProvider dans LaunsedUrlClassloadher
La classe publique LaunchEDUrlClassloader étend URLClassLoader {private static LockProvider Lock_Provider = setuplockProvider (); LockProvider statique privé SetUplockProvider () {try {classloader.RegisterAsParallCapable (); retourner le nouveau java7lockProvider (); } catch (nosuchMethoDerror ex) {return new LockProvider (); }} @Override Protected Class <?> LoadClass (nom de chaîne, Boolean Resolve) lève ClassNotFoundException {synchronisé (lancédUrlClassLoader.lock_provider.getLock (this, name)) {class <?> LoadEdClass = findloadClass (name); if (chardedClass == null) {handler.setUseFastConnectionExceptions (true); try {chardedClass = doloAdClass (name); } enfin {handler.setUseFastConnectionExceptions (false); }} if (résolve) {ResolVeClass (LoadedClass); } return chardedClass; }} Vérifiez si le package JAR est chargé via l'agent
InputArgumentsJavaAgentDetector, le principe est de détecter si l'URL du JAR a le préfixe de "-javaagent:".
chaîne finale statique privée java_agent_prefix = "-javaagent:";
Obtenez le PID du processus
ApplicationPid, vous pouvez obtenir le PID.
String privé getpid () {try {String jvmName = ManagementFactory.getRuntiMemXBean (). getName (); return jvmname.split ("@") [0]; } catch (Throwable ex) {return null; }} Classe d'enregistrement d'emballage
Spring Boot a un ensemble de journalistes qui prennent en charge Java, Log4j, Log4j2, Logback. Vous pouvez vous référer à cela lorsque vous devez emballer vous-même vos bûcherons à l'avenir.
Sous le package org.springframework.boot.logging.
Obtenez la fonction principale du démarrage d'origine
Grâce à la méthode obtenue dans la pile, jugez la fonction principale et trouvez la fonction principale démarrée d'origine.
classe privée <?> DeduceMainApplicationClass () {try {stackTraceElement [] stackTrace = new RuntimeException (). getStackTrace (); for (stackTraceElement stackTraceElement: stackTrace) {if ("main" .equals (stackTraceElement.getMethodName ())) {return class.forname (stackTraceElement.getClassName ()); }}} catch (classNotFoundException ex) {// avaler et continuer} return null;} Quelques inconvénients de la botte en spirng:
Lorsque l'application Spring Boot s'exécute dans un pot de gros, certains problèmes seront rencontrés. Voici mes opinions personnelles:
Résumer
Spring Boot étend le protocole de JAR, résume le concept d'archives et le jarfile de support, le jarurlconnection et le lancementdUrlClassloader, réalisant ainsi l'expérience de développement de tous en un sans perception de l'application de couche supérieure. Bien que la guerre exécutable ne soit pas un concept proposé par Spring, Spring Boot permet de le faire avancer.
Spring Boot est un projet incroyable, qui peut être considéré comme le deuxième printemps du printemps. Spring-Cloud-Config, Spring-Session, Metrics, Remote Shell, etc. sont tous des projets et des fonctionnalités que les développeurs aiment. Il est presque certain que le concepteur possède une riche expérience dans le développement de première ligne et est bien conscient des points de douleur des développeurs.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.