Ps: Really suitable for reading source code for beginners to see SpringBoot source code, if you really want to read SpringBoot source code, you can follow the following recommended way to read the article

  1. Open the IDE, open the SpringBoot source code, write comments along with the article, write your own comments
  2. Don’t be too tangled did not say where, after all, SpringBoot source so much, want to finish all is impossible, as long as follow the article read carefully, SpringBoot is how to run must have a more profound understanding
  3. The article should be read in full, not in a skip. It’s easy to miss important things when you skip
  4. Again, if you haven’t read the previous article, it’s best to read the previous article first
  5. Read the source code must not be a large section of the source code, must be patient, do not turn over things, is often the longest method is really need to learn
  6. If not, please encourage me with likes, favorites and comments

SpringBoot source code beginners (A) : The use of SpringBoot function extension interface and source analysis

First, listener mode

In the way of learning to follow some principles, can be more effective learning, including such a “shoot” steps, to know what is before you in deep SpringBoot listener, the listener is how to implement, these are all against the great Lord of magic, and RPG games to play before you boss MOBS upgraded, The “dragon slaying sword”. As an adventurer on the continent of Varora, Izarel was constantly affected by the weather, so he asked me to write a software program to help him keep an eye on the weather.

1, listener mode small demo! Weather monitor

Step 1: Create the abstract WeatherEvent class

public abstract class weatherEvent{
    // Get the weather status
    public abstract String getWeather(a);
}
Copy the code

Step 2: Implement snow and rain events Snow events

public class SnowEvent extends WeatherEvent{
    @Overide
    public String getWeather(a){
        return "It's snowing"; }}Copy the code

Rain events

public class RainEvent extends WeatherEvent{
    @Overide
    public String getWeather(a){
        return "It's raining."; }}Copy the code

Step 3: Create the weather listener interface

public interface WeatherListener{
    void onWeatherEvent(WeatherEvent event);
}
Copy the code

Step 4: realize the monitor, and deal with the snowy and rainy weather respectively. When it snows, it is necessary to put on large cotton-padded jacket and wear gloves to keep out the cold

public class SnowListener implements WeatherListener{
    @Override
    public void onWeatherEvent(WeatherEvent event){
        if(event instanceof SnowEvent){
            event.getWeather();
            System.out.println("It's snowing! Please add clothes and protect yourself from the cold!"); }}}Copy the code

When it rains, you need to bring an umbrella and wear rain shoes

public class RainListener implements WeatherListener{
    @Override
    public void onWeatherEvent(WeatherEvent event){
        if(event instanceof RainEvent){
            event.getWeather();
            System.out.println("It's raining today! Please take your umbrella when you go out."); }}}Copy the code

Step 5: Create the broadcaster interface

public interface EventMulticaster{
    // Broadcast events
    void multicastEvent(WeatherEvent event);
    // Add a listener
    void addListener(WeatherListener weaterListener);
    // Delete the listener
    void removeListener(WeatherListener weaterListener);
}
Copy the code

Step 6: The abstract class implements the broadcast interface

public abstract class AbstractEventMulticaster implements EventMulticaster{
    // Store a collection of listeners where all events that need to be listened for are stored
    private List<WeaterListener> listenerList = new ArrayList<>();

    @Override
    public void multicastEvent(WeatherEvent event){
        // Using the template approach, subclasses can implement doStart and doEnd, extending before and after the listener call, respectively
        //SpringBoot has a number of similar operations
        // The pre-processor and post-processor in SpringBoot are implemented this way
        doStart();
        // Loop through the onWeatherEvent method that calls all listeners
        listenerList.forEach(i -> i.onWeatherEvent(evnet));
        doEnd();
    }
    
    @Override
    public void addListener(WeatherListener weaterListener){
        listenerList.add(weaterListener);
    }
    
    @Override
    public void removeListener(WeatherListener weaterListener){
        listenerList.remove(weaterListener);
    }
    
    abstract void doStart(a);
    abstract void doEnd(a);
}
Copy the code

Step 7: Broadcast weather events

public class WeatherEventMulticaster extends AbstractEventMulticaster{
    @Override
    void doStart(a){
        System.out.println("Start broadcasting the weather!");
    }
    
    @Override
    void doEnd(a){
        System.out.println("Over! Over!"); }}Copy the code

Step 8: Test and trigger a broadcast

public class Test{
    public static void main(String[] args){
        // Create a broadcaster
        WeatherEventMulticaster eventMulticaster = new WeatherEventMulticaster();
        // Create a listener
        RainListener rainListener = new RainListener();
        SnowListener snowListener = new SnowListener();
        // Add a listener
        eventMulticaster.addListener(rainListener);
        eventMulticaster.addListener(snowListener);
        
        // Trigger a rain event
        eventMulticaster.multicastEvent(new RainEvent());
        // Unless it snows
        eventMulticaster.multicastEvent(newSnowEvent()); }}Copy the code

2. Hemerdinger Lecture Hall, listener mode mechanism explanation

Izelere’s adventures were finally no longer disturbed by the weather, but he did not understand why the small thing was so magical. He asked me many times, but I was a sassy man with poor language and could not express such a complex idea clearly. He had to ask his old friend Hemerdinger to help explain.

Ps: Work should not only can realize the function, but also pay attention to the expression ability, at the time of the interview are able to express ideas clearly can get a higher salary, in the understanding of communication and testing when can help test principle, test out hidden in the depths of the bugs, as a talented programmers, of course, everyone is not a bug, affirmation is caused by environmental problems or improper operation.

Hemerdinger took the code, took a quick look at it and figured out what each module was doing:

  • Events: Step 1 and Step 2, by abstracting the weather and implementing rain and snow weather states
  • Listener: Step 3 and Step 4, standardize the weather monitoring mode, and standardize the corresponding weather, how to deal with
  • Announcer: step 5, Step 6, and step 7. When an event occurs, the announcer sends a signal to inform all listeners, and the listeners act accordingly. Trigger rain event, rain monitor received a message, it looked up to see dark clouds thunder and lightning, slightly one leng, shout 1: “thunder rain clothes ah!!” The announcer goes on to tell the next listener, the snow listener, the snow listener looks up at the sky, waves his hand, and says, “It’s none of my business go find someone else.”
  • Trigger mechanism: Step 8 is triggered in the form of hard coding used in the demo. In practice, the hygrometer may detect the humidity surge and start to rain, and trigger the broadcast.

Among the 23 design patterns, there is no listener pattern. The listener pattern is an implementation of the observer pattern. Both names are misleading. In effect, the broadcast pushes the event to all listeners, and each listener decides and processes the event.

Implementation of SpringBoot event listener

ApplicationListener interface

ApplicationListener is part of Spring’s event mechanism. It works with the abstract Class ApplicationEvent to implement the event mechanism of ApplicationContext. When ApplicationContext triggers an event, the listener is used to notify all classes that implement the ApplicationListener interface.

// This annotation indicates that the current class has only one method
@FunctionalInterface
// The generic type passed in indicates the type of event the listener needs to listen for
// the inherited EventListener class, which is an empty class, declares that the inherited class is an EventListener
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}
Copy the code

It’s not hard to see that the ApplicationListener interface is almost the same as the weather listener we implemented in Step 3, and if you understand the purpose of the little Demo class, you should be familiar with it.

2, ApplicationEventMulticaster interface

ApplicationEventMulticaster is Spring event mechanism of radio interface, all radio apparatus need to implement this interface, the main function is to manage all listeners, and push the event to the listener.

public interface ApplicationEventMulticaster {
    
    // Add a listener
	void addApplicationListener(ApplicationListener
        listener);

    // Add a listener according to beanName
	void addApplicationListenerBean(String listenerBeanName);

    // Remove a listener
	void removeApplicationListener(ApplicationListener
        listener);

    // Remove a listener based on beanName
	void removeApplicationListenerBean(String listenerBeanName);

    // Remove all listeners
	void removeAllListeners(a);

    // A method for broadcasting events
	void multicastEvent(ApplicationEvent event);

	void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
Copy the code

SpringBoot’s 7 biggest events

[picture archived failure outside the chain, the source station might be hotlinking prevention mechanism, proposed to directly upload picture preserved (img – cu6pwkNo – 1585491460589) (en – resource: / / database / 2523:1)]

  • EventObject: Event top-level object, the root object of all event objects
  • ApplicationEvent: ApplicationEvent
  • SpringApplicationEvent: Spring’s own events, the Spring framework’s own events implement this interface
  • ApplicationStartingEvent: The start event that is emitted as soon as the framework starts
  • ApplicationEnvironmentPreparedEvent: changes in the environment to complete, the system properties and the user to specify already loaded
  • ApplicationContextInitializedEvent: has created the context, and haven’t loaded any beans before the event
  • ApplicationPreparedEvent: Fired after the Bean definition has started loading, before it is fully loaded, and before the context is refreshed
  • ApplicationStartedEvent: The bean has been created and the context has been refreshed, but the ApplicationRunner and CommandLineRunne extension interfaces have not been executed
  • ApplicationReadyEvent: Triggered when the ApplicationRunner and CommandLineRunne extension interfaces are executed
  • ApplicationFailedEvent: Triggered when startup exceptions occur

(1) Sequence of events

Start – > ApplicationStartingEvent – “ApplicationContextInitializedEvent ApplicationEnvironmentPreparedEvent -” -” ApplicationPreparedEvent – ApplicationStartedEvent – ApplicationReadyEvent – is started

An exception occurs. – ApplicationFailedEvent – Startup fails

4, event listener source analysis

(1) Listener registration process

If you read the previous article “SpringBoot source beginners (a) : SpringBoot function extension interface use and source analysis” : https://juejin.cn/post/6844904106843193357 here is easy to understand, A complete reading can just don’t want to have a look at the factory loading mechanism part of the source code parsing and ApplicationContextInitializer interface exactly the same process to register, Only change ApplicationContextInitializer interface to the ApplicationListener interface

Let’s go back to the main method we started with. Step 1: View the SpringBoot boot class

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        // Go to the source of the run methodSpringApplication.run(Application.class, args); }}Copy the code

Step 2: Here you can see a simple layer of calls

public static ConfigurableApplicationContext run(Class
        primarySource, String... args) {
       // Go to the method of the same name and continue poking the run method
		return run(newClass<? >[] { primarySource }, args); }Copy the code

Step 3: Here’s where it gets interesting. Pay attention to the comments

public static ConfigurableApplicationContext run(Class
       [] primarySources, String[] args) {
       // Click the SpringApplication constructor
		return new SpringApplication(primarySources).run(args);
}
Copy the code

Step 4: No useful encapsulation, reuse of constituent functions

public SpringApplication(Class
       ... primarySources) {
       // Click this to view the constructor
		this(null, primarySources);
}
Copy the code

Step 5: here we can see two familiar names getSpringFactoriesInstances method and ApplicationContextInitializer interface

public SpringApplication(ResourceLoader resourceLoader, Class
       ... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
       / / here is according to an article on the registered ApplicationContextInitializer interface
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
       // This is where ApplicationListener is registered. You can see that the main difference is the interface class of the query
       //setListeners are stored in containers in a list property for future use
       // This object's AbstractEventMulticaster class corresponds to the list in the demo's AbstractEventMulticaster class
       / / getSpringFactoriesInstances method, a reference articles "SpringBoot function expand the use of the interface and source code analysis,
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
}
Copy the code

(2) Listener triggers process

Step 1: View the SpringBoot boot class

@SpringBootApplication
public class Application {
    public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code

Step 2: ConfigurableApplicationContext class

public static ConfigurableApplicationContext run(Class
        primarySource, String... args) {
		return run(newClass<? >[] { primarySource }, args); }Copy the code

Step 3: Enter the run method this time

public static ConfigurableApplicationContext run(Class
       [] primarySources, String[] args) {
       // Click the run method
		return new SpringApplication(primarySources).run(args);
}
Copy the code

Step 4: every time I see this approach, all feel it sinful, how many people since it began to look at, on reading the source code Code is longer, this is not write all comments, specific comments here at https://juejin.cn/post/6844904106843193357

	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
        // Get the event runner
        / / SpringApplicationRunListeners internal contains a SpringApplicationRunListener (there s no) collection
        There are 7 big events / / SpringApplicationRunListener execution method, the corresponding site is called, SpringBoot through the implement event trigger
        //SpringBoot comes with an implementation that executes seven defined events
        / / user may by implementing SpringApplicationRunListener interface, defined in the corresponding event needed to execute commands
        // The overall process is very simple, I leave it to you to read
		SpringApplicationRunListeners listeners = getRunListeners(args);
        // This is where the listener story begins, and where our story begins this time
        // Enter the starting method
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}
Copy the code

Step 5: No thousand-layer routines

public void starting(a) {
    / / to store all the listeners inside SpringApplicationRunListener (event trigger)
   for (SpringApplicationRunListener listener : this.listeners) {
        // Loop through the starting method of the event trigger
        // How does SpringBoot's event trigger worklistener.starting(); }}Copy the code

Step 6: The broadcaster sends events

@Override
	public void starting(a) {
        //initialMulticaster is a broadcaster
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}
Copy the code

Step 7: The broadcaster sends events

@Override
	public void starting(a) {
        //initialMulticaster is a broadcaster
        // Enter the multicastEvent method
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}
Copy the code

Step 8: When broadcasting an event, determine the type of the event and whether it needs to be executed at this time point

@Override
public void multicastEvent(ApplicationEvent event) {
    / / resolveDefaultEventType method, parse event of default type
    // Go to the resolveDefaultEventType method, step 9
    // Go to the multicastEvent method, step 11
   multicastEvent(event, resolveDefaultEventType(event));
}
Copy the code

Step 9: Get the event type

private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
    // Get the event type
    // Enter the forInstance method, step 10
    return ResolvableType.forInstance(event);
}
Copy the code

Step 10: Check the time type through the interface

public static ResolvableType forInstance(Object instance) {
    // If instance is empty, stop SpringBoot and report an error
    Assert.notNull(instance, "Instance must not be null");
    // Check whether the ResolvableTypeProvider interface is implemented
    // the ResolvableTypeProvider interface indicates that the event type of this class can be resolved
    if (instance instanceof ResolvableTypeProvider) {
        // Force the type ResolvableTypeProvider and get the event type
        ResolvableType type = ((ResolvableTypeProvider) instance).getResolvableType();
        if(type ! =null) {
            // If the event type is not empty, return it directly
            returntype; }}// Return a default instance type. Wrap the instance type as ResolvableType and return it
    // Return to Step 8
    return ResolvableType.forClass(instance.getClass());
}
Copy the code

Step 11: Start broadcasting two parameters: event: indicates the event to be executed. EventType: indicates the event type

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    // If the event type is empty, execute the resolveDefaultEventType method (steps 9 and 10).ResolvableType type = (eventType ! =null ? eventType : resolveDefaultEventType(event));
    // Get the thread pool for the task's execution
    // If not specified, return null, SpringBoot is empty
    Executor executor = getTaskExecutor();
    / / getApplicationListeners method, get the listener interested in this event
    // Click the getApplicationListeners method to go to Step 12
    for(ApplicationListener<? > listener : getApplicationListeners(event, type)) {if(executor ! =null) {
            // Triggers on the specified thread
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            // Triggers by defaultinvokeListener(listener, event); }}}Copy the code

Parameter description: Event: indicates the current event. This method is to find the listener that is interested in this event. EventType: indicates the event type

protectedCollection<ApplicationListener<? >> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) {// Get the source class from which the event occurred, in this case SpringApplication
   Object source = event.getSource();
   // Get the type of the original headerClass<? > sourceType = (source ! =null ? source.getClass() : null);
   // Get the cache key
   ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

   // Execute quickly to fetch listeners from the cache. If this method has already been executed, do not fetch again
   ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
   if(retriever ! =null) {
        // Returns the listener interested in the current event
      return retriever.getApplicationListeners();
   }

   if (this.beanClassLoader == null ||
         (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
               (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
      // Lock by key. This is a very effective way to lock. Define an attribute as the key of the lock
      synchronized (this.retrievalMutex) {
        // After locking, check again to see if the current event is triggered elsewhere, putting the list of listeners into the cache
        // The singleton pattern that has written two-layer validation is familiar here, and the main principle is the same
         retriever = this.retrieverCache.get(cacheKey);
         if(retriever ! =null) {
            // Returns the listener interested in the current event
            return retriever.getApplicationListeners();
         }
         retriever = new ListenerRetriever(true);
         // The real lookup logic is encapsulated here
         //SpringBoot is a cache wrapper, and the next one is an actual call
         // We can learn when programming, such as encapsulating cached query, then go to the database, reduce coupling degree
         / / some retrieveApplicationListeners method into step 13Collection<ApplicationListener<? >> listeners = retrieveApplicationListeners(eventType, sourceType, retriever);// Store it in cache
         this.retrieverCache.put(cacheKey, retriever);
         returnlisteners; }}else {
      // Do not need to lock, and do not need to cache the query mode
      / / this method two calls the retrieveApplicationListeners method, the method of internal for presence of cache, do the different treatment
      // Personal opinion: The internal cache logic should be moved to this layer, otherwise the coupling is still very high
      return retrieveApplicationListeners(eventType, sourceType, null); }}Copy the code

Step 13: Actually get the logic of the listener

privateCollection<ApplicationListener<? >> retrieveApplicationListeners( ResolvableType eventType,@NullableClass<? > sourceType,@NullableListenerRetriever retriever) { List<ApplicationListener<? >> allListeners =newArrayList<>(); Set<ApplicationListener<? >> listeners; Set<String> listenerBeans;synchronized (this.retrievalMutex) {
        // Get all listener instances
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        // Get the beanName of all listeners
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }
    // Loop through all listeners one by one
    for(ApplicationListener<? > listener : listeners) {// Determine whether the listener is interested in this event
        // Click the supportsEvent method to go to Step 14
        if (supportsEvent(listener, eventType, sourceType)) {
            if(retriever ! =null) {
                // If the listener function is caching enabled, it is stored in the cache
                retriever.applicationListeners.add(listener);
            }
            // Cache or no cache will be stored hereallListeners.add(listener); }}// Get the listener from the factory
    if(! listenerBeans.isEmpty()) {// Get the bean factory
        BeanFactory beanFactory = getBeanFactory();
        // Loop listener beanName
        for (String listenerBeanName : listenerBeans) {
            try {
                // Use beanName to get the type of listenerClass<? > listenerType = beanFactory.getType(listenerBeanName);// Determine whether the listener is interested in this event
                if (listenerType == null || supportsEvent(listenerType, eventType)) {
                    // Get the bean instance. This method is written getBean and read createBean
                    // This is a very important piece of ioc logic. When a bean cannot be retrieved, a bean object is created
                    // We will explain the details in the follow-up IOC source code analysisApplicationListener<? > listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);if(! allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {// Is also the logic to determine whether there is a cache
                        if(retriever ! =null) {
                            // Add one more logic to determine whether or not a singleton exists
                            if (beanFactory.isSingleton(listenerBeanName)) {
                                retriever.applicationListeners.add(listener);
                            }
                            else {
                                // The original bean is called "multiple examples". It is better to call it "prototype".retriever.applicationListenerBeans.add(listenerBeanName); } } allListeners.add(listener); }}}catch (NoSuchBeanDefinitionException ex) {
               
            }
        }
    }
    // Sort, SpringBoot's usual operation, according to the Order interface or annotations
    AnnotationAwareOrderComparator.sort(allListeners);
    // Refresh the cache to clear the previous results and cache the results of this run
    if(retriever ! =null && retriever.applicationListenerBeans.isEmpty()) {
        retriever.applicationListeners.clear();
        retriever.applicationListeners.addAll(allListeners);
    }
    // Returns the acquired listener
    // Return to Step 12
    return allListeners;
}
Copy the code

Step 14: Determine whether the listener is interested in the current event

protected boolean supportsEvent( ApplicationListener
        listener, ResolvableType eventType, @Nullable Class
        sourceType) {
    / / was undertaken to determine whether the listener, GenericApplicationListener subclass
    // The event starting is not a subclass
    / / GenericApplicationListener use the decorator pattern
    // The famous decorator pattern is Java IO stream (inputStream etc.)
    / / GenericApplicationListener can parse the ApplicationListener generic parameters of the interface, the interface is as follows:
    // "ApplicationListener
      
       " if you can't remember, go back to the little Demo above and the description of this interface
      
    GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
            (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
    // The following is simple, although the internal judgment is very complicated, overall only two things are done
    SupportsEventType: Determines whether the listener supports the current event
    //supportsSourceType: Whether the listener is interested in the event's originating class
    // Returns a total bool, returning step 13
    return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
Copy the code

5. Customize SpringBoot listener

(1) Inject with spring.factories

Step 1: Create a listener and implement the ApplicationListener interface

// We make this listener interested in the ApplicationStartedEvent event
@Order(1)
public class TestListener implements ApplicationListener<ApplicationStartedEvent>{
    @Ovrride
    public void onApplicationEvent(ApplicationStartedEvent event){
        System.out.println("hello, Application start is over"); }}Copy the code

Step 2: in the spring. The implementation class is added to the factories, guidance Here comes a, also not friends stab here, hurriedly brushing up: https://juejin.cn/post/6844904106843193357

#com.gyx.test.Listener is the full pathname of the Listener you just wrote
org.springframework.context.ApplicationListener=com.gyx.test.TestListener
Copy the code

Then run the program and see that the printed statement appears

(2) Manual injection of SpringApplication

Step 1: Create a listener and implement the ApplicationListener interface as above. Step 2: Modify the SpringBoot boot class

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(Application.class);
        // Add to the initial configuration item
        springApplication.addListeners(newTestListener()); springApplication.run(args); }}Copy the code

(3) Register in the SpringBoot configuration file

Step 1: Create a listener and implement the ApplicationListener interface as above step 2: Modify the configuration file

context.listener.classes=com.gyx.test.TestListener
Copy the code

Friends have seen a lesson, is discovered, and exactly the same as the registered way ApplicationContextInitializer before!!!!!! You’re starting to get a sense of it, so let’s do it while the iron is hot and go back to last time

(4) Multi-event listener, realize the SmartApplicationListener interface

This method only implements the interface is different, the injection method is the same, the above three injection methods can use step 1: create a listener, and implement the SmartApplicationListener interface

@Order(1)
public class TestSmartListener implements SmartApplicationListener{
    @Ovrride
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType){
        // Here is the type judgment, which determines the event that the listener is interested in
        // You can be interested in more than one event. Here, two events are configured
        returnApplicationStartedEvent.class.isAssignableFrom(eventType) || ApplicationPreparedEvent.class.isAssignableFrom(eventType);  }@Ovrride
    public void onApplicationEvent(ApplicationStartedEvent event){
        System.out.println("hello, This is smartApplicationListener"); }}Copy the code