Github address:

Github.com/yuanmabiji/…

SpringBoot event listening mechanism source analysis (on) SpringBoot source code (nine)

1 Review the old and learn the new

We briefly review the content of the last article, which analyzed the principle of broadcasting life cycle events when SpringBoot is started, and now summarize the key steps again:

  1. Pre-preparation for broadcasting SpringBoot built-in lifecycle events: 1) Load firstApplicationListenerListener implementation class; 2) Next load the SPI extension classEventPublishingRunListener.
  2. SpringBoot is used when startingEventPublishingRunListenerBroadcast life cycle events, and thenApplicationListenerThe listener implementation class listens for the corresponding lifecycle events to perform some initialization logic.

2 the introduction

The previous article focuses on the analysis of SpringBoot boot broadcast life cycle events when the principle, this article we will detailed analysis of SpringBoot built-in 7 kinds of life cycle events source.

SpringBoot life cycle event source code analysis

To analyze SpringBoot’s lifecycle events, let’s start with a class structure diagram:The relationship between event classes can be seen from the figure above:

  1. The top-level parent class is the JDK’s event base classEventObject;
  2. Then Spring’s event base classApplicationEventInherits the EVENT base class of the JDKEventObject;
  3. Second, SpringBoot’s lifecycle event base classSpringApplicationEventInheriting from Spring’s event base classApplicationEvent;
  4. Finally, SpringBoot’s seven lifecycle event classes inherit SpringBoot’s lifecycle event base classSpringApplicationEvent.

3.1 The JDK’s event base class EventObject

The EventObject class is the JDK’s event base class, which can be said to be the basic of all Java event classes, that is, all Java event classes are directly or indirectly inherited from the class, the source code is as follows:

// EventObject.java

public class EventObject implements java.io.Serializable {

    private static final long serialVersionUID = 5516075349620653480L;

    /** * The object on which the Event initially occurred. */
    protected transient Object  source;
    /**
     * Constructs a prototypical Event.
     *
     * @param    source    The object on which the Event initially occurred.
     * @exception  IllegalArgumentException  if source is null.
     */
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");
        this.source = source;
    }
    /**
     * The object on which the Event initially occurred.
     *
     * @return   The object on which the Event initially occurred.
     */
    public Object getSource(a) {
        return source;
    }
    /**
     * Returns a String representation of this EventObject.
     *
     * @return  A a String representation of this EventObject.
     */
    public String toString(a) {
        return getClass().getName() + "[source=" + source + "]"; }}Copy the code

You can see that the EventObject class has only one property, Source, which records the class in which the initial event occurred. For example, the ApplicationStartingEvent event is emitted during SpringBoot. This event is originally emitted in the SpringApplication class, so the Source is the SpringApplication object.

3.2 Spring’s event base class ApplicationEvent

ApplicationEvent inherits the DK event base class EventObject, which is Spring’s event base class.

// ApplicationEvent.java

/**
 * Class to be extended by all application events. Abstract as it
 * doesn't make sense for generic events to be published directly.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
public abstract class ApplicationEvent extends EventObject {
	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = 7099057708183571937L;
	/** System time when the event happened. */
	private final long timestamp;
	/**
	 * Create a new ApplicationEvent.
	 * @param source the object on which the event initially occurred (never {@code null})
	 */
	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}
	/** * Return the system time in milliseconds when the event happened. */
	public final long getTimestamp(a) {
		return this.timestamp; }}Copy the code

You can see that ApplicationEvent has one and only one attribute, TIMESTAMP, which is used to record when the event occurred.

3.3 SpringBoot event base class SpringApplicationEvent

The SpringApplicationEvent class inherits Spring’s event base class ApplicationEvent, which is the parent of all SpringBoot built-in lifecycle events. The source code is as follows:


/**
 * Base class for {@link ApplicationEvent} related to a {@link SpringApplication}.
 *
 * @author Phillip Webb
 */
@SuppressWarnings("serial")
public abstract class SpringApplicationEvent extends ApplicationEvent {
	private final String[] args;
	public SpringApplicationEvent(SpringApplication application, String[] args) {
		super(application);
		this.args = args;
	}
	public SpringApplication getSpringApplication(a) {
		return (SpringApplication) getSource();
	}
	public final String[] getArgs() {
		return this.args; }}Copy the code

As you can see, SpringApplicationEvent has one and only one property, args, which is the command-line argument to SpringBoot startup, the argument to the main function in the @SpringBootApplication startup class.

3.4 SpringBoot specific life cycle event classes

Let’s take a look at SpringBoot’s built-in lifecycle events, the specific subclasses of SpringApplicationEvent.

3.4.1 track ApplicationStartingEvent

// ApplicationStartingEvent.java

public class ApplicationStartingEvent extends SpringApplicationEvent {
	public ApplicationStartingEvent(SpringApplication application, String[] args) {
		super(application, args); }}Copy the code

The ApplicationStartingEvent event is published when SpringBoot starts. It is published before the Environment variable Environment or container ApplicationContext is created but after the ApplicationListener specific listener is registered. The flag marks the start of SpringApplication.

3.4.2 ApplicationEnvironmentPreparedEvent

// ApplicationEnvironmentPreparedEvent.java

public class ApplicationEnvironmentPreparedEvent extends SpringApplicationEvent {
	private final ConfigurableEnvironment environment;
	/**
	 * Create a new {@link ApplicationEnvironmentPreparedEvent} instance.
	 * @param application the current application
	 * @param args the arguments the application is running with
	 * @param environment the environment that was just created
	 */
	public ApplicationEnvironmentPreparedEvent(SpringApplication application, String[] args, ConfigurableEnvironment environment) {
		super(application, args);
		this.environment = environment;
	}
	/**
	 * Return the environment.
	 * @return the environment
	 */
	public ConfigurableEnvironment getEnvironment(a) {
		return this.environment; }}Copy the code

Can see ApplicationEnvironmentPreparedEvent events much an environment attributes, we might as well think about it, how about the role of the environment attribute is what? The answer is ApplicationEnvironmentPreparedEvent environment attribute of the role is to use events publish-subscribe mechanism, The corresponding listener can be extracted from ApplicationEnvironmentPreparedEvent events environment variables, and then we can take care of the environment increase attribute values or read values of environment variables.

Here’s an example: ConfigFileApplicationListener a ApplicationEnvironmentPreparedEvent event listener is listening, Then remove them ApplicationEnvironmentPreparedEvent environment attributes of events, and then increase the application for the environment attribute. The properties in the configuration file environment variable values.

After SpringApplication has started and the Environment variable Environment has been created, and Environment variables of the command line and Servlet types have been configured for the Environment variable, At this time will release ApplicationEnvironmentPreparedEvent events.

Listening to the first listener is ConfigFileApplicationListener ApplicationEnvironmentPreparedEvent events, Because is ConfigFileApplicationListener listener and increased application Environment variable Environment properties in the configuration file Environment variables; Since there are a few other listeners to monitor is to monitor ApplicationEnvironmentPreparedEvent events to the event, at this point to say the Environment variable Environment has almost completely ready.

Think about it: listeners that listen to the same event execute the listening logic in order. We can think about when the sorting logic is sorted. And why do we do that?

Rule 3.4.3 ApplicationContextInitializedEvent

// ApplicationContextInitializedEvent.java

public class ApplicationContextInitializedEvent extends SpringApplicationEvent {
	private final ConfigurableApplicationContext context;
	/**
	 * Create a new {@link ApplicationContextInitializedEvent} instance.
	 * @param application the current application
	 * @param args the arguments the application is running with
	 * @param context the context that has been initialized
	 */
	public ApplicationContextInitializedEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context) {
		super(application, args);
		this.context = context;
	}
	/**
	 * Return the application context.
	 * @return the context
	 */
	public ConfigurableApplicationContext getApplicationContext(a) {
		return this.context; }}Copy the code

Can see ApplicationContextInitializedEvent events much ConfigurableApplicationContext type of context attributes, The context property is also used so that listeners can access the context property to perform some logic, as described in 3.4.4.

After the ApplicationContext container to create ApplicationContextInitializedEvent events, And set the environment variable for ApplicationContext containers and perform the initialization method of ApplicationContextInitializers but in bean definitions triggered before loading, Indicates that ApplicationContext has been initialized.

Extension: Can see ApplicationContextInitializedEvent is triggered after as the context container configuration environment variables, Containers ApplicationContextInitializedEvent at this time as long as there are events such as the context, then other listeners need environment environment variable from the context to retrieve the environment variables, Thus ApplicationContextInitializedEvent events such as there is no need to configure the environment attributes.

3.4.4 ApplicationPreparedEvent

// ApplicationPreparedEvent.java

public class ApplicationPreparedEvent extends SpringApplicationEvent {
	private final ConfigurableApplicationContext context;
	/**
	 * Create a new {@link ApplicationPreparedEvent} instance.
	 * @param application the current application
	 * @param args the arguments the application is running with
	 * @param context the ApplicationContext about to be refreshed
	 */
	public ApplicationPreparedEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context) {
		super(application, args);
		this.context = context;
	}
	/**
	 * Return the application context.
	 * @return the context
	 */
	public ConfigurableApplicationContext getApplicationContext(a) {
		return this.context; }}Copy the code

Can also see ApplicationPreparedEvent events more a ConfigurableApplicationContext types of context attributes, the context attribute is used to monitor the event listeners are able to get the context attribute, When a listener gets the context attribute, it usually does the following:

  1. Fetch from the eventcontextProperty, and then you can add some post-handlers likeConfigFileApplicationListenerThe listener listensApplicationPreparedEventAfter the event, then removecontextVariable, bycontextThe variable goes upPropertySourceOrderingPostProcessorThis post-processor;
  2. throughcontextAttribute to take out thebeanFactoryContainer, and then register somebean, such asLoggingApplicationListenerListener passApplicationPreparedEventThe eventcontextAttribute to take out thebeanFactoryContainer, and then registeredspringBootLoggingSystemThe singletonbean;
  3. throughcontextAttribute to take out theEnvironmentEnvironment variables, and then you can manipulate environment variables, for examplePropertiesMigrationListener.

The ApplicationPreparedEvent event is fired when the ApplicationContext container is fully ready but before the container is refreshed, at which point the bean definition has been loaded and the Environment is ready for use.

3.4.5 ApplicationStartedEvent

// ApplicationStartedEvent.java

public class ApplicationStartedEvent extends SpringApplicationEvent {
	private final ConfigurableApplicationContext context;
	/**
	 * Create a new {@link ApplicationStartedEvent} instance.
	 * @param application the current application
	 * @param args the arguments the application is running with
	 * @param context the context that was being created
	 */
	public ApplicationStartedEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context) {
		super(application, args);
		this.context = context;
	}
	/**
	 * Return the application context.
	 * @return the context
	 */
	public ConfigurableApplicationContext getApplicationContext(a) {
		return this.context; }}Copy the code

The ApplicationStartedEvent event is fired after the container is refreshed but before the Run methods of ApplicationRunner and CommandLineRunner are executed, indicating that the Spring container has been refreshed and that the container is ready.

Extension: What are the ApplicationRunner and CommandLineRunner interfaces mentioned here for? When static data such as system parameters needs to be loaded after the Spring container is refreshed, the ApplicationRunner or CommandLineRunner interface can be implemented to load static data.

3.4.6 ApplicationReadyEvent

// ApplicationReadyEvent.java

public class ApplicationReadyEvent extends SpringApplicationEvent {
	private final ConfigurableApplicationContext context;
	/**
	 * Create a new {@link ApplicationReadyEvent} instance.
	 * @param application the current application
	 * @param args the arguments the application is running with
	 * @param context the context that was being created
	 */
	public ApplicationReadyEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context) {
		super(application, args);
		this.context = context;
	}
	/**
	 * Return the application context.
	 * @return the context
	 */
	public ConfigurableApplicationContext getApplicationContext(a) {
		return this.context; }}Copy the code

The ApplicationReadyEvent event is emitted after the ApplicationRunner and CommandLineRunner run methods are called, indicating that the SpringApplication is already running.

3.4.7 ApplicationFailedEvent

// ApplicationFailedEvent.java

public class ApplicationFailedEvent extends SpringApplicationEvent {
	private final ConfigurableApplicationContext context;
	private final Throwable exception;
	/**
	 * Create a new {@link ApplicationFailedEvent} instance.
	 * @param application the current application
	 * @param args the arguments the application was running with
	 * @param context the context that was being created (maybe null)
	 * @param exception the exception that caused the error
	 */
	public ApplicationFailedEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context, Throwable exception) {
		super(application, args);
		this.context = context;
		this.exception = exception;
	}
	/**
	 * Return the application context.
	 * @return the context
	 */
	public ConfigurableApplicationContext getApplicationContext(a) {
		return this.context;
	}
	/**
	 * Return the exception that caused the failure.
	 * @return the exception
	 */
	public Throwable getException(a) {
		return this.exception; }}Copy the code

As you can see, the ApplicationFailedEvent event has a context property and a Throwable exception property that records exceptions when SpringBoot fails to start.

The ApplicationFailedEvent event is triggered when SpringBoot fails to start.

4 summary

This article is relatively simple, with a detailed analysis of seven life cycle events built into SpringBoot. Again, let’s review these lifecycle events and their purpose using a diagram from the previous article:

5 at the end

Because some friends suggested before some source analysis article is too long, resulting in insufficient patience, can not go down, therefore, after the source analysis article if too long, I will consider splitting into several articles, so it is shorter, easier to read, hey hey.

Github address:

Github.com/yuanmabiji/…