Jedes Spring Boot-Projekt verfügt über eine Hauptprogramm-Startklasse. In der Hauptprogramm-Startklasse gibt es eine main()-Methode zum Starten des Projekts. Mit dieser Methode kann das gesamte Spring Boot-Programm durch Ausführen von SpringApplication.run() gestartet werden. .
Frage: Wie startet die SpringApplication.run()-Methode das Spring Boot-Projekt?
Sehen wir uns den Quellcode innerhalb der run()-Methode an. Der Kerncode lautet wie folgt:
@SpringBootApplication public class SpringbootDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootDemoApplication.class, args); } }
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class[]{primarySource}, args); } public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }
Wie aus dem obigen Quellcode ersichtlich ist, führt die SpringApplication.run()-Methode intern zwei Operationen aus, nämlich die erste Durch die Erstellung und den Aufruf der SpringApplication-Instanz wird das Projekt gestartet. Die Implementierung dieser beiden Phasen wird wie folgt beschrieben
Sehen Sie sich die Quellcodeinformationen zur Initialisierung und Erstellung des SpringApplication-Instanzobjekts an. Der Kerncode lautet wie folgt:
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { this.sources = new LinkedHashSet(); this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.isCustomEnvironment = false; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // 把项目启动类.class设置为属性存储起来 this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // 判断当前webApplicationType应用的类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 设置初始化器(Initializer),最后会调用这些初始化器 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 设置监听器(Listener) this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); // 用于推断并设置项目main()方法启动的主程序启动类 this.mainApplicationClass = this.deduceMainApplicationClass();
Wie aus dem obigen Quellcode ersichtlich ist, umfasst der Initialisierungsprozess von SpringApplication hauptsächlich 4 Teile: und die spezifische Beschreibung ist wie folgt.
(1) this.webApplicationType = WebApplicationType.deduceFromClasspath()
wird verwendet, um den Typ der aktuellen webApplicationType-Anwendung zu bestimmen. Mit der Methode deduceFromClasspath() wird überprüft, ob eine bestimmte Feature-Class unter dem Classpath-Klassenpfad vorhanden ist, um festzustellen, ob der aktuelle webApplicationType-Typ eine SERVLET-Anwendung (traditionelle MVC-Anwendung vor Spring 5) oder eine REACTIVE-Anwendung (interaktive WebFlux-Anwendung) ist das begann im Frühjahr 5 zu erscheinen)
(2) this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class))
Für Initialisierungseinstellungen der SpringApplication-Anwendung. Während des Initialisierungsprozesses wird der Spring-Klassenlader SpringFactoriesLoader verwendet, um alle verfügbaren Anwendungsinitialisierungsklassen ApplicationContextInitializer aus der Datei spring.factores unter META-INF im Klassenpfad META-INF/spring.factories abzurufen.
(3) this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class))
Wird für Listener-Einstellungen der SpringApplication-Anwendung verwendet. Der Listener-Einstellungsprozess ist im Wesentlichen derselbe wie der Initialisierungsprozess im vorherigen Schritt. SpringFactoriesLoader wird auch verwendet, um alle verfügbaren Listener-Klassen ApplicationListener aus der spring.factores-Datei unter META-INF unter dem Klassenpfad META-INF/spring.factories abzurufen .
(4) this.mainApplicationClass = this.deduceMainApplicationClass()
Wird verwendet, um die Startklasse des Hauptprogramms abzuleiten und festzulegen, die durch die Methode main() des Projekts gestartet wurde
Nach der Analyse der ersten Erstellung des SpringApplication-Instanzobjekts im vorherigen Teil des Quellcodes (new SpringApplication(primarySources)).run(args) überprüfen Sie den von run(args) ausgeführten Startvorgang für die Projektinitialisierung )-Methode. Der Kerncode lautet wie folgt:
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); // 第一步:获取并启动监听器 SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 第二步:根据SpringApplicationRunListeners以及参数来准备环境 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); // 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体 Banner printedBanner = this.printBanner(environment); // 第三步:创建Spring容器 context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, new Object[]{context}); // 第四步:Spring容器前置处理 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 第五步:刷新容器 this.refreshContext(context); // 第六步:Spring容器后置处理 this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } // 第七步:发出结束执行的事件 listeners.started(context); // 返回容器 this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners) null); throw new IllegalStateException(var9); } }
Wie aus dem obigen Quellcode ersichtlich ist, umfasst der Projektinitialisierungs- und Startvorgang ungefähr die folgenden Teile:
Schritt 1: Besorgen und starten Sie den Listener
This.getRunListeners Die Methoden (args) und listeners.starting() werden hauptsächlich zum Abrufen von SpringApplication-Instanzen verwendet. Der SpringApplicationRunListener-Listener wird während des Initialisierungsprozesses initialisiert und ausgeführt.
Schritt 2: Bereiten Sie die Umgebung gemäß SpringApplicationRunListeners und Parametern vor
Diese.prepareEnvironment(listeners, applicationArguments)-Methode wird hauptsächlich verwendet, um die Projektlaufumgebung voreinzustellen und gleichzeitig einige unnötige Vorgänge durch this.configureIgnoreBeanInfo(environment) auszuschließen. Methodenumgebung
Schritt 3: Erstellen Sie einen Spring-Container
Bestimmen Sie den Containertyp anhand von webApplicationType. Wenn der Typ SERVLET ist, wird der entsprechende Bytecode durch Reflektion geladen, nämlich AnnotationConfigServletWebServerApplicationContext, und dann den zuvor initialisierten Kontextsatz verwenden (Anwendungskontext), Umgebung (Projektlaufumgebung), Listener (laufende Listener), applicationArguments (Projektparameter) und printBanner (Projektsymbolinformationen) stellen den Anwendungskontext zusammen, konfigurieren ihn und aktualisieren die Konfiguration
Schritt 4: Vor dem Spring-Container-Setup Verarbeitung
Dieser Schritt ist hauptsächlich eine vorbereitende Maßnahme vor der Auffrischung des Behälters. Richten Sie die Containerumgebung ein, einschließlich verschiedener Variablen usw., einschließlich eines sehr wichtigen Vorgangs: Injizieren Sie die Startup-Klasse in den Container, um die Grundlage für die nachfolgende automatisierte Konfiguration zu legen. Schritt 5: Aktualisieren Sie den Container durch die Aktualisierung Initialisieren Sie den gesamten IOC-Container (einschließlich Positionierung der Bean-Ressourcen, Analyse, Registrierung usw.) und registrieren Sie einen Shutdown-Hook bei der JVM-Laufzeit. Dieser Kontext wird geschlossen, wenn die JVM heruntergefahren wird Damals
Schritt 6: Spring-Container-Nachbearbeitung
Erweiterungsschnittstelle, Vorlagenmethode im Entwurfsmuster, standardmäßig leere Implementierung. Wenn Sie benutzerdefinierte Anforderungen haben, können Sie diese Methode überschreiben. Zum Beispiel das Drucken einiger Start- und Abschlussprotokolle oder eine andere Nachbearbeitung.
Schritt 7: Geben Sie ein Ereignis aus, das die Ausführung beendet. Holen Sie sich den EventPublishingRunListener-Listener, führen Sie seine gestartete Methode aus, übergeben Sie den erstellten Spring-Container, erstellen Sie ein ApplicationStartedEvent-Ereignis und führen Sie die
publishEvent-Methode von ConfigurableApplicationContext aus besagt, dass Ereignisse im Spring-Container und nicht in SpringApplication veröffentlicht werden. Dies unterscheidet sich vom vorherigen Start. Das Startereignis wird direkt an den Listener in SpringApplication veröffentlicht.
Schritt 8: Läufer ausführen
Wird verwendet, um die benutzerdefinierte Executor-Klasse XxxRunner im Projekt aufzurufen, um einige bestimmte Programme unmittelbar nach dem Start des Projekts auszuführen. Zu den von Spring Boot bereitgestellten Executor-Schnittstellen gehören ApplicationRunner und CommandLineRunner. Bei der Verwendung müssen Sie nur eine Executor-Klasse anpassen, um eine der Schnittstellen zu implementieren und die entsprechende run()-Methodenschnittstelle neu zu schreiben Sofort gestartet. Führen Sie diese spezifischen Programme aus
Nachfolgend können Sie anhand eines Spring Boot-Ausführungsdiagramms den gesamten Ausführungsprozess und die wichtigsten Startphasen von Spring Boot besser verstehen:
Das obige ist der detaillierte Inhalt vonBeispielanalyse des SpringBoot-Ausführungsprozesses. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!