Github address:
Github.com/yuanmabiji/…
How is the SpringApplication object built in this article? SpringBoot source code (eight)
1 Review the old and learn the new
Review the past, let’s briefly review the content of the last article, the last article we analyzed the SpringApplication object construction process and SpringBoot itself to achieve a set of SPI mechanism, now the key steps are condensed summary:
SpringApplication
The process of constructing an object is essentially givingSpringApplication
Of the class6Member variable assignment;- SpringBoot implements its own SPI mechanism through the following steps:
- 1) First get the thread context classloader;
- 2) Then use the context class loader from
spring.factories
In the configuration fileLoad all SPI extension implementation classes and put them in the cache; - 3) Retrieve the corresponding SPI extension implementation class from the cache according to SPI interface;
- 4) Instantiate the SPI extension implementation class taken from the cache and return it.
2 the introduction
During SpringBoot startup, each startup phase broadcasts a different built-in lifecycle event, And then the corresponding listener will listen to these events to perform some initialization logic work such as ConfigFileApplicationListener will monitor onApplicationEnvironmentPreparedEvent incident to load the application configuration file. The p Roperties environment variables, etc.
Therefore, this article will analyze the source code of SpringBoot event listening mechanism.
3 SpringBoot broadcast built-in lifecycle event flow analysis
To explore the SpringBoot broadcast built-in lifecycle event flow, let’s review the SpringBoot startup flow code again:
// SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
/ / [0] to create a new SpringApplicationRunListeners object is used to launch SpringBoot started in the process of life cycle events
SpringApplicationRunListeners listeners = getRunListeners(args);
// [1] 》》》》》 emits the ApplicationStartingEvent event to signal the start of SpringApplication
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
/ / [2] "" "" "launch event ApplicationEnvironmentPreparedEvent 】 【, at this time to load the application, the properties such as profile of environment variables, at the same time, there are marks mean environment variable has been prepared
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
/ / [3] "" "" "launch event, ApplicationContextInitializedEvent 】 【 was created and is ready to sign the context container
// [4] 》》》》》 emits the [ApplicationPreparedEvent] event to signal that the Context container is ready
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// [5] 》》》》》 emits an ApplicationStartedEvent event to indicate that the Spring container has been refreshed and all bean instances have been loaded
listeners.started(context);
callRunners(context, applicationArguments);
}
// [6] 》》》》》 launches the ApplicationFailedEvent event, indicating that SpringBoot fails to start
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// [7] 》》》》》 emits the ApplicationReadyEvent event, indicating that the SpringApplication is already running, that it has been successfully started, and can receive service requests.
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
Copy the code
Can see SpringBoot first during the boot process will create a new SpringApplicationRunListeners object is used to launch SpringBoot started in the process of all kinds of life cycle events, Such as emission ApplicationStartingEvent ApplicationEnvironmentPreparedEvent and ApplicationContextInitializedEvent events, The corresponding listener then performs some initialization logic during SpringBoot boot. So when are the listeners listening for these SpringBoot lifecycle events loaded and instantiated? Remember the last article analyzing the SpringApplication build process? Yes, the listeners that perform the initialization logic are loaded and instantiated from the Spring.Factories configuration file according to the ApplicationListener interface during the build of the SpringApplication.
3.1 Prepare for broadcasting SpringBoot built-in life cycle events
3.1.1 Loading the ApplicationListener implementation class
Let’s review again how the SpringApplication object is built. Right? Note the importance of setListeners’ collections of SpringBoot objects getSpringFactoriesInstances(ApplicationListener.class)); This code.
What this does is load the SPI extension implementation class of the ApplicationListener event listener interface from spring.Factories and add it to the Listeners’ collection of SpringApplication objects. Used to listen for subsequent events during SpringBoot startup to perform some initialization logic.
The specific listeners at SpringBoot boot implement the ApplicationListener interface, configured in the Spring.Factories section as follows:
However, when debugging, listeners are loaded from all the Spring.Factories configuration files, and eventually 10 listeners are loaded. The diagram below:
3.1.2 loading class EventPublishingRunListener SPI extension
Said before, in the process of SpringBoot start first will create a new SpringApplicationRunListeners object is used to launch SpringBoot started in the process of life cycle events, What we now see SpringApplicationRunListeners listeners = getRunListeners (args); This code:
// SpringApplication.java
private SpringApplicationRunListeners getRunListeners(String[] args) {
// Construct a types consisting of springApplication.class and String[].classClass<? >[] types =newClass<? >[] { SpringApplication.class, String[].class };/ / 1) according to SpringApplicationRunListener interface to spring. Factories in the configuration file to load it expand SPI implementation class
/ / 2) build a SpringApplicationRunListeners object and return
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
Copy the code
We will focus on getSpringFactoriesInstances (SpringApplicationRunListener. Class, types, this, args) this code, GetSpringFactoriesInstances we already familiar with this method, in the last analysis of SPI SpringBoot mechanism have been detailed analysis of this method. Can see SpringBoot. At this time is according to the SPI interface SpringApplicationRunListener to spring loaded in the factories of SPI extension implementation class, We go directly to the spring. What are the factories see SpringApplicationRunListener SPI implementation class:
As can be seen from the picture above,SpringApplicationRunListener
onlyEventPublishingRunListener
This SPI implementation classEventPublishingRunListener
This buddy is particularly important during the SpringBoot startup process. It sends different SpringBoot lifecycle events at different stages of the SpringBoot startup process.namelySpringApplicationRunListeners
The object is not responsible for broadcasting the event, but is ultimately the delegateEventPublishingRunListener
This guy’s here to broadcast the event.
Because from spring. Factories in loading EventPublishingRunListener will instantiate the class after class, so we’ll follow up EventPublishingRunListener source, How does it assume the responsibility of firing SpringBoot life cycle events?
// EventPublishingRunListener.java
public class EventPublishingRunListener implements SpringApplicationRunListener.Ordered {
private final SpringApplication application;
private final String[] args;
/ * * * have a SimpleApplicationEventMulticaster radio apparatus to broadcast events * /
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
/ / create a new event broadcast SimpleApplicationEventMulticaster object
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// Iterate over the event listeners obtained from the Spring.Factories configuration file when constructing the SpringApplication object
for(ApplicationListener<? > listener : application.getListeners()) {// Add the event listeners obtained from the Spring.Factories configuration file to the related collection of the event broadcaster initialMulticaster object
this.initialMulticaster.addApplicationListener(listener); }}@Override
public int getOrder(a) {
return 0;
}
// 》》》》》 emits the ApplicationStartingEvent event
@Override
public void starting(a) {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
/ / "" "" "launch event ApplicationEnvironmentPreparedEvent 】 【
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
/ / "" "" "launch event ApplicationContextInitializedEvent 】 【
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(
this.application, this.args, context));
}
// 》》》》》 fires the ApplicationPreparedEvent event
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for(ApplicationListener<? > listener :this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(
new ApplicationPreparedEvent(this.application, this.args, context));
}
// 》》》》》 launches the ApplicationStartedEvent event
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(
new ApplicationStartedEvent(this.application, this.args, context));
}
// 》》》》》 emits the ApplicationReadyEvent event
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(
new ApplicationReadyEvent(this.application, this.args, context));
}
// 》》》》》 fires the ApplicationFailedEvent event
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application,
this.args, context, exception);
if(context ! =null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for(ApplicationListener<? > listener : ((AbstractApplicationContext) context) .getApplicationListeners()) {this.initialMulticaster.addApplicationListener(listener); }}this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event); }}/ /... Omit non-critical code
}
Copy the code
You can see EventPublishingRunListener class implements the SpringApplicationRunListener interface, SpringApplicationRunListener interface defines SpringBoot startup launch interface method of life cycle events, And EventPublishingRunListener class is by implementing the interface SpringApplicationRunListener starting, environmentPrepared and contextPrepared to broadcast Sprin GBoot different life cycle events, we see SpringApplicationRunListener directly interface source code:
// SpringApplicationRunListener.java
public interface SpringApplicationRunListener {
void starting(a);
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void started(ConfigurableApplicationContext context);
void running(ConfigurableApplicationContext context);
void failed(ConfigurableApplicationContext context, Throwable exception);
}
Copy the code
Then analysis EventPublishingRunListener this class, we can see its members have an important attribute initialMulticaster, the member attribute is SimpleApplicationEventMulticaster class object, This class is to assume the radio SpringBoot starts the responsibilities of life cycle events, namely EventPublishingRunListener objects not broadcast events of responsibility, And the final is entrusted SimpleApplicationEventMulticaster this elder brothers to broadcast events. From EventPublishingRunListener source can also be seen in the starting, environmentPrepared and contextPrepared method is by calling SimpleApplicationEventMultic The Aster class object’s multicastEvent method broadcasts events.
Thinking SpringBoot launch when events in the process of start broadcasting is layers of entrusted responsibility, shall be borne by SpringApplicationRunListeners object at first, Then SpringApplicationRunListeners object will broadcast events responsibility entrusted to EventPublishingRunListener object, Eventually EventPublishingRunListener object responsibilities entrusted to SimpleApplicationEventMulticaster objects will broadcast events. Why do you delegate this? It’s worth thinking about.
Previously from spring. After loading the EventPublishingRunListener class will be instantiated in the factories, and instantiate inevitably through the constructor to instantiate EventPublishingRunListener, So we then analysis the EventPublishingRunListener constructor source code:
// EventPublishingRunListener.java
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
/ / create a new event broadcast SimpleApplicationEventMulticaster object
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// Iterate over the event listeners obtained from the Spring.Factories configuration file when constructing the SpringApplication object
for(ApplicationListener<? > listener : application.getListeners()) {// Add the event listeners obtained from the Spring.Factories configuration file to the related collection of the event broadcaster initialMulticaster object
this.initialMulticaster.addApplicationListener(listener); }}Copy the code
Can see in the constructor of EventPublishingRunListener have a for loop traverses from spring. Before loading in the factories of the listener, then added to the collection of cached and used for later broadcast events directly from this collection to remove. You don’t have to load it in spring.factories.
3.2 Broadcast SpringBoot’s built-in lifecycle events
From spring. Factories in the configuration file to load and instantiate EventPublishingRunListener object, so in SpringBoot will launch a series of in the process of start SpringBoot built-in life cycle events, Let’s review the source code in the SpringBoot boot process again:
// SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
/ / [0] to create a new SpringApplicationRunListeners object is used to launch SpringBoot started in the process of life cycle events
SpringApplicationRunListeners listeners = getRunListeners(args);
// [1] 》》》》》 emits the ApplicationStartingEvent event to signal the start of SpringApplication
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
/ / [2] "" "" "launch event ApplicationEnvironmentPreparedEvent 】 【, at this time to load the application, the properties such as profile of environment variables, at the same time, there are marks mean environment variable has been prepared
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
/ / [3] "" "" "launch event, ApplicationContextInitializedEvent 】 【 was created and is ready to sign the context container
// [4] 》》》》》 emits the [ApplicationPreparedEvent] event to signal that the Context container is ready
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// [5] 》》》》》 emits an ApplicationStartedEvent event to indicate that the Spring container has been refreshed and all bean instances have been loaded
listeners.started(context);
callRunners(context, applicationArguments);
}
// [6] 》》》》》 launches the ApplicationFailedEvent event, indicating that SpringBoot fails to start
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// [7] 》》》》》 emits the ApplicationReadyEvent event, indicating that the SpringApplication is already running, that it has been successfully started, and can receive service requests.
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
Copy the code
Can see in the process of SpringBoot startup will launch a total of seven different types of life cycle events, to signal SpringBoot different startup phase, at the same time, the life cycle event listener who will perform some startup initialization logic, in the process of initialization logic about the listener will be in the next piece of content analysis. The following are the types of events to be emitted during SpringBoot startup. ApplicationFailedEvent is emitted only when an exception occurs during SpringBoot startup:
ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationContextInitializedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationFailedEvent
ApplicationReadyEvent
With our listeners. Starting (); This code, for example, look at EventPublishingRunListener object launch event source code:
// SpringApplicationRunListeners.java
public void starting(a) {
/ / traversal listeners collection, the essence out here is just from the spring. The factories to retrieve the SPI implementation class EventPublishingRunListener
/ / object and EventPublishingRunListener undertook the SpringBoot responsible for broadcasting the different life cycle events in the process of start
for (SpringApplicationRunListener listener : this.listeners) {
/ / call EventPublishingRunListener starting method to broadcast ApplicationStartingEvent eventslistener.starting(); }}Copy the code
Follow up listener.starting(); Source:
EventPublishingRunListener.java
// 》》》》》 emits the ApplicationStartingEvent event
public void starting(a) {
/ / EventPublishingRunListener object will release ApplicationStartingEvent this matter entrusted to the initialMulticaster object
// Call the initialMulticaster multicastEvent method to emit the ApplicationStartingEvent event
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
Copy the code
As you can see, EventPublishingRunListener object will release ApplicationStartingEvent this matter entrusted to the initialMulticaster SimpleApplicationEventMulticaster object, And the initialMulticaster object will eventually call its multicastEvent method to emit the ApplicationStartingEvent event event. How about SimpleApplicationEventMulticaster class broadcast events, the author has the Spring mechanism is how to implement the event listeners? This article has been analyzed in detail and will not be repeated here.
Source code for launching other life cycle events during SpringBoot startup is no longer analyzed here
4 SpringBoot’s built-in lifecycle event summary
Now that we have analyzed the various life cycle events to be emitted during the SpringBoot startup process, the following table summarizes them:
5 subtotal
This concludes the source code analysis of broadcast lifecycle events during SpringBoot startup, and the next article will continue to cover the listeners that listen for these lifecycle events. Let’s review this article and summarize the key points:
Seven types of lifecycle events are emitted during SpringBoot startup, marking different startup phases, and the appropriate listener listens for these events to perform some initialization logic.
Github source code Analysis project launched!! Here is the Github address of the note:
Github.com/yuanmabiji/…