Vor kurzem habe ich Zeit, die Open API -Plattform des Unternehmens zu optimieren. Als ich das Jar -Paket tippte, stellte ich plötzlich fest, dass ich zuvor sehr in der Verwendung von Spring Stiefel in der Lage war, das Startprinzip des von Spring Boot produzierten Glass nie zu wusste. Dann entpackte ich das Glas diesmal und sah es mir an. Es war wirklich anders als das, was ich mir vorgestellt habe. Das Folgende ist eine vollständige Analyse des nicht gepackten Glass.
Die Anwendung von Spring Start ist nicht veröffentlicht. Die Struktur einer einfacheren Demo ist ähnlich. Zusätzlich ist die Version von Spring Boot, die ich verwendet habe, 1.4.1. Es gibt einen weiteren Artikel im Internet, um das Start von Spring Boot Jar zu analysieren. Das sollte unter 1,4 liegen, und die Startmethode unterscheidet sich auch sehr von der aktuellen Version.
Nach der Installation von MVN Clean, wenn wir in das Zielverzeichnis nachsehen, finden wir wie folgt zwei JAR -Pakete:
xxxx.jarxxx.jar.original
Dies wird auf den Spring-Boot-Plug-in-Mechanismus zurückgeführt, der ein gewöhnliches Glas in ein ausführbares JAR-Paket verwandelt, und xxx.jar.original ist ein von Maven produziertes JAR-Paket. Diese finden Sie in Bezug auf den Artikel auf der offiziellen Spring -Website wie folgt:
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#exexexecutable-jar
Das Folgende ist Teil der Verzeichnisstruktur des von der Spring Boot -Anwendung erzeugten Glas, von denen die meisten weggelassen werden und nur die wichtigen Teile angezeigt werden.
. ├ kurz-inf│ ├── Klassen│ ├── Anwendung-Dev.Properties│ │ ├── Anwendung-prod. " │ │ │ │ │ │ └── SwaggerConfig.class│ │ │ │ │ ├── oauth2│ │ │ │ ├── controller│ │ │ │ │ ├── AccessTokenController.class│ │ ├── logback-spring.xml│ │ └── static│ ├── css│ │ │ └── guru.css│ │ ├── images│ │ ├── FBcover1200x628.png│ │ └── NewBannerBOOTS_2.png│ └── lib│ ├── accessors-smart-1.1.jar├── META-INF│ ├── MANIFEST.MF│ └── maven│ └── com.weibangong.open│ └── Open-Server-Openapi│ ├── └ -Properties│ └─äre POM.xml└└ org └──-SpringFramework └º Boot ├── StartedurlClassloader $ 1.CLASS ├── LOADERLADER.CLASS ├── - Launcher.Class ├── - Archiv │ ├── Archiv $ Eintrag Explodedarchive $ fileEntry.class │ ├── explodedarchive $ fileEntryiterator $ EntryComparator
Zusätzlich zu der Klasse, die wir in der Anwendung geschrieben haben, hat dieses Glas auch ein separates Org -Paket. Es sollte sein, dass die Spring -Boot -Anwendung das Spring -Boot -Plugin verwendet, um dieses Paket einzugeben, um die Paketbühne im MVN -Lebenszyklus zu verbessern. Es ist dieses Paket, das eine Schlüsselrolle im Startprozess spielt. Darüber hinaus werden die verschiedenen Abhängigkeiten, die von der Anwendung benötigt werden, in das Glas eingegeben und das zusätzliche Paket des Spring -Starts wird eingegeben. Dieses Glas, das All-in-One kann, heißt auch Fat.jar. Hier werden wir immer Fat.jar verwenden, um den Namen des Glass zu ersetzen.
Zu diesem Zeitpunkt werden wir uns weiterhin die Manifest.mf-Datei in Meta-inf ansehen, wie folgt:
Manifest-Version: 1.0Implementation-Title: Open :: Server :: OpenAPIImplementation-Version: 1.0-Snapshotarchiver-Version: Plexus Archiversbuilt-by: Xiaxuanimplementation-Vendor-ID: Com.Weibangong.openspring-Version: 1.4.1.1. Inc.Main-Klasse: org.springframework.boot.loader.PropertieSlaunchStart-Klasse: com.weibangong.open.openapi.springbootwebapplicationspring-boot-Klasse: Boot-inf/classs/Spring-Boot-lib: boot-inf/lib/lib/erstellt: apache: apache maven 3.3.9buil-j-inf/lib/erstellt/by: apache mellen 3.3.9build: 1.8.0_20Implementation-url: http://maven.apache.org/open-server-openapi
Die hier angegebene Hauptklasse ist eine Klassendatei in dem Paket, das anstelle unseres Startprogramms separat eingegeben wird, und dann hat die Manifest.mf-Datei eine separate Startklasse, die das Startprogramm unserer Anwendung angibt.
Zuerst finden wir die Klasse org.springframework.boot.loader.propertieSlauncher, wo die Hauptmethode lautet:
public static void main (String [] args) löst eine Ausnahme aus {PropertieSlauncher Launcher = new PropertieSlauncher (); args = launcher.getArgs (args); Launcher.launch (Args);}Überprüfen Sie die Startmethode. Diese Methode befindet sich im Überklassen -Launcher und die Startmethode der Elternklasse lautet wie folgt:
Protected Void Launch (String [] Args, String -Mainclass, Classloader Classloader) löst Ausnahme aus {Thread.currentThread (). setContextClassloader (Classloader); this.CreateMainMethodrunner (Mainclass, Args, Classloader) .run (); } Protected MainMethodrunner CreateMainMethodrunner (String mellClass, String [] args, classloader classloader) {return New MainMethodrunner (Mainclass, Args); }Die Startmethode ruft schließlich die CreateMainMethodrunner -Methode auf, die das MainMethodrunner -Objekt instanziiert und die Run -Methode ausführt. Wir gehen wie folgt zum Quellcode des Mainmethodrunner -Quells:
Paket org.springframework.boot.loader; importieren java.lang.reflect.method; public class MainMethodrunner {private endgültige String -MainclassName; private endgültige Zeichenfolge [] Argumente; public MainMethodrunner (String mellClass, String [] args) {this.mainClassName = mellClass; this.args = args == null? null: (string []) args.clone (); } public void run () löst Ausnahme aus {class mainclass = thread.currentThread (). getContextClassloader (). LoadClass (this.mainClassName); Methode MainMethod = mellClass.getDeclaredMethod ("main", New Class [] {String []. Klasse}); MainMethod.Invoke ((Objekt) null, neues Objekt [] {this.args}); }}Wenn Sie die Run -Methode überprüfen, ist es sehr einfach, das Spring -Boot -Glas auszuführen, und die Analyse ist im Grunde genommen vorbei.
5. Der Startprozess des Hauptprogramms
Nachdem wir über den Startprozess von JAR gesprochen haben, sprechen wir über den Start- und Ladevorgang des Hauptprogramms in der Spring -Boot -Anwendung. Schauen wir uns zunächst die Hauptmethode der Spring -Boot -Anwendung an.
Paket cn.com.devh; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootApplication; importieren org.springFramework.cloud.client.discovery.EnableInsCoccoveryClient; Importieren; org.springframework.cloud.netflix.eureka.enableeureKaclient; import org.springframework.cloud.netflix.fegn.EnableFeignClients;/*** Erstellt von Xiaxuan am 17.01.25. */@SpringBootApplication@enableFeignclients@enableEureKaClientPublic Klasse A1ServiceApplication {public static void main (String [] args) {Springapplication.run (a1ServiceApplication.Class, Args); }}Gehen Sie wie folgt zur Run -Methode in Springapplication:
/** * statischer Helfer, mit dem eine {@link SpringApplication} aus der angegebenen Quelle mit Standardeinstellungen ausgeführt werden kann. * @param Quelle Die Quelle zum Laden * @param argumentiert die Anwendungsargumente (normalerweise über eine Java -Hauptmethode übergeben) * @return Die laufende {@link applicationContext} */ public static configurableApplicationContext Run (Objektquelle, String ... Args) {Return Run (New Object [] {Source}, args, args); } /** * statischer Helfer, mit dem ein {@link SpringApplication} aus den angegebenen Quellen mit Standardeinstellungen und benutzergelieferten Argumenten ausgeführt werden kann. * @param Quellen Die Quellen zum Laden * @param argumentieren die Anwendungsargumente (normalerweise über eine Java -Hauptmethode übergeben) * @return die laufende {@link applicationContext} */ public static ConfigurableApplicationContext Run (Object [] Quellen, String [] args) {Neue SpringApplication zurückgeben (Quellen) .run (Argumente); }Hier ist die Instanziierung der Springapplication der Schlüssel, wir gehen zum Spring Application Constructor.
/*** Erstellen Sie eine neue {@link SpringApplication} Instanz. Der Anwendungskontext wird * Beans aus den angegebenen Quellen geladen (siehe Dokumentation {@link SpringApplication Class-Level} * für Details. Die Instanz kann vor dem Aufrufen von * {@link #run (String ...)} angepasst werden. SpringApplication (Objekt ... Quellen) {initialisieren (Quellen); GetSpingFactoryStances (ApplicationContextInitializer.Class));Absocewebenvironment () in der initialisierenden Methode hier bestimmt, ob sie derzeit wie folgt mit einer Webanwendung oder einem normalen Glas gestartet wird:
private boolean schließewebenvironment () {für (String className: web_environment_classeses) {if (! classutils.isspresent (className, null)) {return false; }} return true; }Die web_environment_classes lautet:
private statische endgültige String [] web_environment_classes = {"javax.servlet.servlet", "org.springFramework.web.context.ConfigurableableWebApplicationContext"};Solange eine von ihnen nicht existiert, wird die aktuelle Anwendung in Form eines normalen Glass gestartet.
Dann initialisiert die SetInitializers -Methode alle ApplicationContextInitializer,
/** * legt den {@link applicationContextInitializer} fest, der auf die Spring * {@link applicationContext} angewendet wird. * @param initializer die initializer zu set */ public void setInitializers (sammeln <? erweitert applicationContextInitializer <? >> Initializer {this.initializer = new ArrayList <ApplicationContextInitializer <>> (); this.initializer.addall (Initialisierer); } setListeners ((Sammlung) GetSPringFactoresInstances (applicationListener.class)) **Dieser Schritt initialisiert alle Zuhörer.
Kehren wir zur vorherigen Spring Application (Quellen) zurück (Argumente); und geben Sie die Auslaufmethode ein, der Code ist wie folgt:
/** * Führen Sie die Spring -Anwendung aus, erstellen und aktualisieren Sie eine neue * {@link applicationContext}. * @param args die Anwendungsargumente (normalerweise über eine Java -Hauptmethode übergeben) * @return A Laufen {@link applicationContext} */ public configurableApplicationContext run (String ... args) {stopwatch stopwatch = new stopwatch (); stopwatch.start (); ConfigurableApplicationContext context = null; configureHeadlessProperty (); SpringApplicationRunListeners Hörer = getrunListeners (Args); Hörer.Started (); try {applicationArgumente applicationArgumente = new DefaultApplicationArgumente (Args); context = CreateAndReFreshContext (Hörer, applicationArgumente); AfterRefresh (Kontext, applicationArgumente); Hörer. stopwatch.stop (); if (this.logstartupinfo) {New StartUpInfologger (this.mainApplicationClass) .LogStarted (getApplicationog (), Stoppwatch); } Rückgabekontext; } catch (throwable ex) {HandlerunFailure (Kontext, Hörer, ex); neue IllegalStateException (Ex) werfen; }}Dieser Schritt führt die Kontext -Erstellung CreateandReFreshContext (Hörer, ApplicationArgumente) aus,
private configurableApplicationContext createAndreFreshContext (SpringApplicationRunListeners -Hörer, ApplicationArgumente ApplicationArgumente) {configurableApplicationContext -Kontext; // die Umgebung für die Umgebung erstellen und konfigurieren konfigurieren Umweltumgebung = GetOrCreateEnvironment (); configureEnvironment (Umgebung, applicationArguments.getSourceargs ()); Zuhörer. Umweltgeräte (Umwelt); if (iswebenvironment (Umgebung) &&! this.webenvironment) {Environment = convertTOSTANDARDARDIRMEND (Umwelt); } if (this.BannerMode! } // Erstellen, Laden, Aktualisieren und Ausführen des ApplicationContext context = createApplicationContext (); context.setEnvironment (Umwelt); postProcessapplicationContext (Kontext); applyInitializer (Kontext); Hörer.ContextPreparared (Kontext); if (this.logstartUpInfo) {logStartUpInfo (context.getParent () == null); logStartupproFileInfo (Kontext); } // Startspezifischer Singleton Beans Context.getBeArtory (). Regietersingleton ("SpringApplicationArgumente", applicationArgumente); // Laden Sie die Quellen SET <Object> Sources = Getources (); Assert.notEmpty (Quellen, "Quellen dürfen nicht leer sein"); Load (Kontext, Quellen.ToArray (neues Objekt [Quellen.Size ()])); listener.Contextload (Kontext); // den Kontext aktualisieren (Kontext); if (this.registerShutDownhook) {try {context.registerShutDownhook (); } catch (AccessControlException ex) {// in einigen Umgebungen nicht zulässig. }} Rückgabekontext; } // Erstellen und Konfigurieren der Umgebung für Konfigurieren von Umgebungen für konfigurierende Umwelt = GetOrCreateEn -Umgebung (); configureEnvironment (Umgebung, applicationArguments.getSourceargs ());Dieser Schritt führt die Konfiguration und das Laden der Umgebung durch.
if (this.BannerMode! }
Dieser Schritt druckt das Spring -Boot -Logo. Wenn Sie es ändern müssen, fügen Sie der Ressourcendatei Banner.txt und Banner.txt hinzu, um sie in das von Ihnen benötigte Muster zu ändern.
// den ApplicationContext context = createApplicationContext () erstellen, laden, aktualisieren und ausführen; return (configurableApplicationContext) beanutils.instantiate (contextClass)
Der Erstellungskontext enthält wirklich, was Container erstellt wird, und die Reaktionsklasse instanziiert, einschließlich der Erstellung von EmbeddedServletContainerFactory, ob Sie Jetty oder Tomcat auswählen, es gibt viele Inhalte, daher werde ich das nächste Mal darüber sprechen.
if (this.registerShutDownhook) {try {context.registerShutDownhook (); } catch (AccessControlException ex) {// in einigen Umgebungen nicht zulässig. }}Dieser Schritt soll den aktuellen Kontext registrieren und den Container zerstören, wenn der Befehl Kill empfangen wird.
Grundsätzlich ist die Startanalyse vorbei, aber es gibt immer noch einige Details, die sehr zeitaufwändig zu erzählen sind. Dies wird im nachfolgenden Blog -Beitrag diskutiert, und das ist alles für heute.
Zusammenfassend ist der Startprozess von Spring Boot Jar im Grunde die folgenden Schritte:
1. Wenn wir Maven normalerweise verpacken, erweitert das Spring-Boot-Plug-In den Lebenszyklus von Maven und verleiht das Paket mit Spring Boot in das Glas. Dieses Glas enthält Klassendateien im Zusammenhang mit dem Spring Boot Startup -Programm neben den von der Anwendung erstellten Gläser.
2. Ich habe den Startprozess einer etwas niedrigeren Version von Spring Boot Jar schon einmal gesehen. Zu diesem Zeitpunkt erinnere ich mich, dass der aktuelle Thread einen neuen Thread zum Ausführen des Hauptprogramms hat, und jetzt wurde er geändert, um die Reflexion direkt zu verwenden, um das Hauptprogramm zu starten.
Zusammenfassen
Die oben genannte ist die Analyse des Prinzips von Spring Boot Jar, das Ihnen vom Herausgeber vorgestellt wurde. Ich hoffe, es wird Ihnen hilfreich sein. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Editor wird Ihnen rechtzeitig antworten. Vielen Dank für Ihre Unterstützung auf der Wulin.com -Website!