From: juejin. Cn/post / 684490…

An overview of the

We all know that the Spring source code is extensive and difficult to read. One reason is that there are a lot of internal listeners, spring-related frameworks, spring Security, springBoot, etc. Today we’ll look at springBoot listener applications.

Because springBoot is an encapsulation of Spring, the application of springBoot listeners is mainly in the boot module.

The source code

SpringBoot listeners fall into two main categories:

1) Runtime listener

# Run Listenersorg.springframework.boot.SpringApplicationRunListener=\ Org. Springframework. Boot. Context. Event. EventPublishingRunListener duplicate codeCopy the code

2) Context listeners

# Application Listenersorg.springframework.context.ApplicationListener=\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ Org. Springframework. Boot. Logging. LoggingApplicationListener duplicate codeCopy the code

Note: springBoot runtime listeners are used to trigger springBoot context listeners, which are distinguished according to the events monitored by each listener. The default listener does the following:

Both runtime listeners and context listeners are defined in the Spring.Factories file.

Listener firing

The startup process has been analyzed in detail in the previous two articles, so in this article we will only look at the listener logic.

public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); / / to get start the listener listener SpringApplicationRunListeners listeners = getRunListeners (args); // Start all listeners with the listeners. Started (); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); context = createAndRefreshContext(listeners, applicationArguments); afterRefresh(context, applicationArguments); listeners.finished(context, null); stopWatch.stop();if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            returncontext; } catch (Throwable ex) { handleRunFailure(context, listeners, ex); throw new IllegalStateException(ex); }} Copy the codeCopy the code

SpringApplicationRunListeners listeners = getRunListeners(args); Here to create a key categories: SpringApplicationRunListeners.

SpringApplicationRunListeners

This is a wrapper utility class that wraps all startup class listeners. Encapsulated into the List by default, there is only one instance here < SpringApplicationRunListener > listeners, mainly convenience we expand, we can define your own start the listener.

/ / start the listener private final List < SpringApplicationRunListener > listeners; SpringApplicationRunListeners(Loglog,
            Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log; this.listeners = new ArrayList<SpringApplicationRunListener>(listeners); } // Start context event listener public voidstarted() {
        for(SpringApplicationRunListener listener : this.listeners) { listener.started(); Public void environmentPrepared(ConfigurableEnvironment environment) {for(SpringApplicationRunListener listener : this.listeners) { listener.environmentPrepared(environment); }} / / spring context ready event listeners public void contextPrepared (ConfigurableApplicationContext context) {for(SpringApplicationRunListener listener : this.listeners) { listener.contextPrepared(context); }} / public/context configuration class loading event listeners void contextLoaded (ConfigurableApplicationContext context) {for(SpringApplicationRunListener listener : this.listeners) { listener.contextLoaded(context); }} / public/context to construct complete event listeners void finished (ConfigurableApplicationContext context, Throwable exception) {for(SpringApplicationRunListener listener : this.listeners) { callFinishedListener(listener, context, exception); }} Copy the codeCopy the code

As described in the source analysis of the startup process, these methods trigger execution at the appropriate point in time and then broadcast different events.

With in EventPublishingRunListener:

public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; / / spring mechanism universal events issued class enclosing multicaster = new SimpleApplicationEventMulticaster ();for(ApplicationListener<? > listener : application.getListeners()) { this.multicaster.addApplicationListener(listener); }} Copy the codeCopy the code

It will default to create global event publishing tools SimpleApplicationEventMulticaster.

@Override
    public void started() {
        publishEvent(new ApplicationStartedEvent(this.application, this.args));
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        publishEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args,
                environment));
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        registerApplicationEventMulticaster(context);
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        for(ApplicationListener<? > listener : this.application.getListeners()) {if(listener instanceof ApplicationContextAware) { ((ApplicationContextAware) listener).setApplicationContext(context); } context.addApplicationListener(listener); } publishEvent(new ApplicationPreparedEvent(this.application, this.args, context)); } @Override public void finished(ConfigurableApplicationContext context, Throwable exception) { publishEvent(getFinishedEvent(context, exception)); } Duplicate codeCopy the code

As you can see, each method publishes different events, all of which inherit from SpringApplicationEvent:

Event broadcast

Follow up on the event broadcast method:

@Override
    public void multicastEvent(ApplicationEvent event) {
        multicastEvent(event, resolveDefaultEventType(event));
    }

    @Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type= (eventType ! = null ? eventType : resolveDefaultEventType(event)); // Select the listener to be notified based on the event typefor(final ApplicationListener<? > listener : getApplicationListeners(event,typeExecutor Executor = getTaskExecutor();if(executor ! = null) { executor.execute(newRunnable() {
                    @Override
                    public void run() { invokeListener(listener, event); }}); }else{ invokeListener(listener, event); }}} copy the codeCopy the code

GetApplicationListeners (event, type)

private Collection<ApplicationListener<? >> retrieveApplicationListeners( ResolvableType eventType, Class<? >sourceType, ListenerRetriever retriever) { //...... // Match listeners by typefor(ApplicationListener<? > listener : listeners) {if (supportsEvent(listener, eventType, sourceType)) {
                if(retriever ! = null) { retriever.applicationListeners.add(listener); } allListeners.add(listener); }} / /... AnnotationAwareOrderComparator.sort(allListeners);returnallListeners; } Duplicate codeCopy the code

SupportsEvent (Listener, eventType, sourceType) :

protected boolean supportsEvent(ApplicationListener<? > listener, ResolvableType eventType, Class<? >sourceType) {/ / to determine whether the listener GenericApplicationListener subclass, If not just return a GenericApplicationListenerAdapter GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); } Duplicate codeCopy the code
public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered { boolean supportsEventType(ResolvableType eventType); boolean supportsSourceType(Class<? >sourceType); } Duplicate codeCopy the code

Here there is a key categories: GenericApplicationListener, this class is provided by the spring used to override the matching event listener interfaces. That is to say if you need to determine the listener is a subclass of GenericApplicationListener, type matching method has been reproduced, will call a subclass matching method. If not, then provide us with a default adapters used to match: GenericApplicationListenerAdapter:

Follow up with the supportsEventType(ResolvableType eventType) method of the class:

public boolean supportsEventType(ResolvableType eventType) {
        if (this.delegate instanceof SmartApplicationListener) {
            Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.getRawClass();
            return ((SmartApplicationListener) this.delegate).supportsEventType(eventClass);
        }
        else {
            return(this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType)); }} Copy the codeCopy the code

Can see the final call is declaredEventType isAssignableFrom (eventType) method, that is to say, if we don’t have to rewrite the listener matching method, The published event is listened to by listeners listening for the event and for its parent class.

Custom listeners

/**
 * Created by zhangshukang on 2018/9/22.
 */
public class SimpleApplicationListener implements GenericApplicationListener,ApplicationListener<ApplicationEvent> {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("myApplistener execute...");
    }

    @Override
    public boolean supportsEventType(ResolvableType eventType) {
        return true; } @Override public boolean supportsSourceType(Class<? >sourceType) {
        return true;
    }

    @Override
    public int getOrder() {
        return0; } Duplicate codeCopy the code

SupportsEventType and supportsSourceType are the reserved extension methods, both of which are true, meaning that all ApplicationEvent events are listened for and executed multiple times:

conclusion

SpringBoot overall framework is through the listener org. Springframework. Boot. SpringApplicationRunListeners, listeners to trigger the context. Context listeners are used to complete the overall logic, such as loading configuration files, loading configuration classes, initializing the logging environment, etc.