An introduction to event-driven models

Event-driven models are also commonly understood as observer or publish/subscribe models.

  • Is a one-to-many relationship between objects;
  • When the target sends a change (publication), the observer (subscriber) receives the change;
  • The target does not interfere in how the observer deals with it, and the relationship between them is loosely coupled.
Event-driven model

There are many examples of event-driven models, such as traffic lights in life, and the configuration hub we use in microservices, where specific application instances are used to update the Spring context when a configuration is committed.

Spring’s event mechanism

The basic concept

Spring’s event-driven model consists of three parts:

  • Event: ApplicationEvent, inherited from EventObject in the JDK, all events will inherit it and get the event source from source.
  • Event publisher: ApplicationEventPublisher and ApplicationEventMulticaster interface, using this interface, our Service has the ability to publish events.
  • Event subscriber: ApplicationListener, inherited from the JDK’s EventListener, which all listeners will inherit.

Spring event driven processes

The event

Spring provides the following implementation by default for the ApplicationEvent event:

  • ContextStoppedEvent: event triggered when ApplicationContext stops;
  • ContextRefreshedEvent: An event triggered after ApplicationContext has been initialized or refreshed;
  • ContextClosedEvent: Event triggered when ApplicationContext is closed. For example, when the Web container is closed, the Spring container is automatically triggered to closectx.registerShutdownHook()Register the hook when the virtual machine is down.
  • ContextStartedEvent: event emitted when ApplicationContext is started;
The event

public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;
    // The time of the event
    private final long timestamp = System.currentTimeMillis();
	// Create a new ApplicationEvent event
    public ApplicationEvent(Object source) {
        super(source);
    }

    public final long getTimestamp(a) {
        return this.timestamp; }}Copy the code

The event base class ApplicationEvent, from which all concrete events inherit.

Event listener

Event listeners

ApplicationListener
EventListener

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}
Copy the code

The onApplicationEvent method is provided to handle ApplicationEvents, although the handling of specific events needs to be determined. While GenericApplicationListener and SmartApplicationListener provides more metadata information about the event.

public class SourceFilteringListener implements GenericApplicationListener.SmartApplicationListener {

	private final Object source;

	@Nullable
	private GenericApplicationListener delegate;

	// Create a SourceFilteringListener for a specific event source and pass in the listener class for the broker
	public SourceFilteringListener(Object source, ApplicationListener
        delegate) {
		this.source = source;
		this.delegate = (delegate instanceof GenericApplicationListener ?
				(GenericApplicationListener) delegate : new GenericApplicationListenerAdapter(delegate));
	}
	/ /... Omit some code
	
	@Override
	public int getOrder(a) {
		return (this.delegate ! =null ? this.delegate.getOrder() : Ordered.LOWEST_PRECEDENCE);
	}

	// The event is actually processed after filtering
	protected void onApplicationEventInternal(ApplicationEvent event) {
		/ /...
		this.delegate.onApplicationEvent(event); }}Copy the code

SourceFilteringListener is a decorator class for ApplicationListener that filters specific event sources. Only the proxy listener corresponding to its event is injected, and functions such as sequentially firing listeners are provided. A portion of ApplicationListener is loaded at startup. After refresh, the Spring Context is loaded and initialized, the ApplicationListener is checked again in the application and registered, When will we implement ApplicationListener will join the Listener the SimpleApplicationEventMulticaster maintenance in the collection. Spring also supports Event listeners in the form of direct annotations @eventListener (event.class).

Event publishing

Publish event

ApplicationContext
ApplicationEventPublisher
AbstractApplicationContext
ApplicationEventMulticaster

@FunctionalInterface
public interface ApplicationEventPublisher {
	// Notify all applications that registered the event. The event can be a framework event such as RequestHandledEvent or a specific application event.
    default void publishEvent(ApplicationEvent event) {
        this.publishEvent((Object)event);
    }

    void publishEvent(Object var1);
}
Copy the code

The actual execution is entrusted, readers are interested can look at this part of the logic in the AbstractApplicationContext. Below we see ApplicationEventMulticaster interface defined in the methods.

public interface ApplicationEventMulticaster {

	// Add listener
	void addApplicationListener(ApplicationListener
        listener);
	/ /...

	// Remove listener
	void removeApplicationListener(ApplicationListener
        listener);
	/ /...
	
	// Broadcast specific events to listeners
	void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);

}
Copy the code

AbstractApplicationContext defines the operation and maintenance of the listener, such as add and remove, and provide a specific event method of broadcasting. Look at the below specific implementation class SimpleApplicationEventMulticaster. ApplicationContext automatically to local container for a ApplicationEventMulticaster implementation, if there is no SimpleApplicationEventMulticaster will use the default.

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	@Nullable
	private Executor taskExecutor;

	/ /...
	
	/ / with a given the beanFactory SimpleApplicationEventMulticaster creation
	public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
		setBeanFactory(beanFactory);
	}

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType ! =null ? eventType : resolveDefaultEventType(event));
		for (finalApplicationListener<? > listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor();if(executor ! =null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else{ invokeListener(listener, event); }}}// Inject the given listener for the given event
	protected void invokeListener(ApplicationListener
        listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if(errorHandler ! =null) {
			try{ doInvokeListener(listener, event); }... }else{ doInvokeListener(listener, event); }}@SuppressWarnings({"unchecked"."rawtypes"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		/ /...}}Copy the code

In the multicastEvent method, you can see that asynchronous publishing of events is supported when executors are not empty. To publish an event, simply call the publishEvent method in ApplicationContext.

conclusion

This article introduces concepts related to the event-driven model in Spring. First, the event-driven model, also known as the observer model, has many applications in our daily life and application development. The Spring event-driven model is composed of three parts: event, publisher and subscriber. The definition and implementation of these three parts are analyzed with Spring source code. In the next article, I will show you how to do this with concrete examples and implementation in Spring Cloud Config.

Subscribe to the latest articles, welcome to follow my official account

reference

  1. An introduction to event-driven models
  2. Spring event-driven model versus observer pattern