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.
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 close
ctx.registerShutdownHook()
Register the hook when the virtual machine is down. - ContextStartedEvent: event emitted when ApplicationContext is started;
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
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
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
- An introduction to event-driven models
- Spring event-driven model versus observer pattern