preface

public SpringApplication(ResourceLoader resourceLoader, Class
       ... primarySources) {
  // Resource loader, null
        this.resourceLoader = resourceLoader;
  // The main class, usually the boot class
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  // Environmental monitoring. Determine whether MVC or WebFlux is enabled
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
  // Set the system initializer
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  // Set the listener
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  // Configure the class in which the main function resides
        this.mainApplicationClass = deduceMainApplicationClass();
}
Copy the code

We are familiar with the system initialization phase of the code above, but we have looked at the source of the system initializer.

In this section, we continue to look at the listener.

Listener mode

This is the first step to understanding one of the design patterns, the observer pattern.

The listener mode is a variation of the observer mode, but it’s the same overall.

The following simple implementation of a listener mode, with a global concept first.

Listener mode elements

  • The event

    Event, which is the object being listened on.

  • The listener

    Listen for events of interest.

  • Radio apparatus

    In charge of broadcast events. Maintain a collection of listeners.

    It broadcasts to all listeners, and when listeners find an event of interest, they perform some logic.

Define events

  1. Event abstraction class

    public abstract class DailyLlifeEvent {
        public abstract String getBehavior(a);
    }
    Copy the code
  2. Fart event

public class FangPiEvent extends DailyLlifeEvent {
    @Override
    public String getBehavior(a) {
        return "fangqi"; }}Copy the code
  1. Shit event
public class LaShiEvent extends DailyLlifeEvent {
    @Override
    public String getBehavior(a) {
        return "lashi"; }}Copy the code

Defining listeners

  1. Listener interface

    public interface DailyLiferListener {
        void onDailyLlifeEvent(DailyLlifeEvent event);
    }
    Copy the code
  2. Fart monitor

    @Component
    public class FangPiListener implements DailyLiferListener {
        @Override
        public void onDailyLlifeEvent(DailyLlifeEvent event) {
            if (event instanceof LaShiEvent) {
                System.out.println("Attention, all of you at home: You."+event.getBehavior()+"The"); }}}Copy the code
  3. Poop monitor

    @Component
    public class LaShiListener implements DailyLiferListener {
        @Override
        public void onDailyLlifeEvent(DailyLlifeEvent event) {
            if (event instanceof LaShiEvent) {
                System.out.println("Septic Tank attention: You"+event.getBehavior()+"The"); }}}Copy the code

Defining broadcast

  1. Broadcast interface

    public interface EventMulticaster {
        void multicastEvent(DailyLlifeEvent event);
        void addListener(DailyLiferListener dailyLiferListener);
        void removeListener(DailyLiferListener dailyLiferListener);
    }
    Copy the code
  2. Broadcast abstract class

    There is also a template approach, which is easy to understand.

    @Component
    public abstract class AbstractEventMulticaster implements EventMulticaster {
       // Inject the subclass listener
        @Autowired
        private List<DailyLiferListener> listenerList;
        @Override
        public void multicastEvent(DailyLlifeEvent event) {
            doStart();
            listenerList.forEach(i -> i.onDailyLlifeEvent(event));
            doEnd();
        }
        @Override
        public void addListener(DailyLiferListener dailyLiferListener) {
            listenerList.add(dailyLiferListener);
        }
        @Override
        public void removeListener(DailyLiferListener dailyLiferListener) {
            listenerList.remove(dailyLiferListener);
        }
        abstract void doStart(a);
        abstract void doEnd(a);
    }
    Copy the code
  3. Broadcast implementation class

    @Component
    public class DailyLifeEventMulticaster extends AbstractEventMulticaster {
        @Override
        void doStart(a) {
            System.out.println("-- on the air -- on the air --");
        }
        @Override
        void doEnd(a) {
            System.out.println("-- End of broadcast end of broadcast --");
        }
        @PostConstruct
        public void postConstruct(a) {
            this.addListener(new FangPiListener());
            this.addListener(newLaShiListener()); }}Copy the code

The effect

All of you at home: You've fangqi over events you're not interested inCopy the code

Listeners in Spring Boot

Setting up listeners

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
Copy the code

Similarly, we go directly to the spring.factories file in Spring Boot to see which listeners ApplicationListener is configured.

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
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.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
Copy the code

Look at what we found, a familiar name DelegatingApplicationListener, initializer section on learning system, we have seen a type named DelegatingApplicationContextInitializer.

If our guess is correct, it works similarly, loading the listener in the configuration and then consuming a wave. Let’s look at the source code.

public class DelegatingApplicationListener implements ApplicationListener<ApplicationEvent>, Ordered {
    private static final String PROPERTY_NAME = "context.listener.classes";
 
    private int order = 0;
 
    private SimpleApplicationEventMulticaster multicaster;
 
  // I was right.
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
    / / monitor the ApplicationEnvironmentPreparedEvent event in the first place
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
      // After this event occurred, the listeners configured in the environment were loaded
            List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
                    ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
            if (delegates.isEmpty()) {
                return;
            }
      // Add the listeners to multicaster
            this.multicaster = new SimpleApplicationEventMulticaster();
            for (ApplicationListener<ApplicationEvent> listener : delegates) {
                this.multicaster.addApplicationListener(listener); }}// Then publish another wave of events that the listener just heard.
        if (this.multicaster ! =null) {
            this.multicaster.multicastEvent(event); }}@SuppressWarnings("unchecked")
    private List<ApplicationListener<ApplicationEvent>> getListeners(ConfigurableEnvironment environment) {
        if (environment == null) {
            return Collections.emptyList();
        }
        String classNames = environment.getProperty(PROPERTY_NAME);
        List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<>();
        if (StringUtils.hasLength(classNames)) {
            for (String className : StringUtils.commaDelimitedListToSet(classNames)) {
                try{ Class<? > clazz = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader()); Assert.isAssignable(ApplicationListener.class, clazz,"class [" + className + "] must implement ApplicationListener");
                    listeners.add((ApplicationListener<ApplicationEvent>) BeanUtils.instantiateClass(clazz));
                }
                catch (Exception ex) {
                    throw new ApplicationContextException("Failed to load context listener class [" + className + "]",
                            ex);
                }
            }
        }
        AnnotationAwareOrderComparator.sort(listeners);
        returnlisteners; }}Copy the code