This article has participated in the Denver Nuggets Creators Camp 3 “More Productive writing” track, see details: Digg project | creators Camp 3 ongoing, “write” personal impact.

Spring provides a very convenient event handling mechanism, including the event class ApplicationEvent and event listener. It implements the designer pattern. If a bean implementing the ApplicationListener interface is deployed in the Spring container, the bean will be notified each time an ApplicationEvent is published to the ApplicationContext.

Beginning with Spring4.2, annotation-based events are provided, meaning that event objects do not have to be extended from ApplicationEvent. Spring automatically wraps this as an event object.

Spring’s standard event description is as follows:

Event explain
ContextRefreshedEvent When initialization or refresh ApplicationContext released on ConfigurableApplicationContext interface (for example, by using the refresh () method). Here, “initialization” means loading all beans, detecting and activating the post-processor beans, pre-instantiating the singleton, and preparing the ApplicationContext object for use. Refresh can be triggered multiple times as long as the context is not closed and as long as the selected ApplicationContext actually supports such a “hot” refresh. XMLWebApplicationContext support, for example, hot flush, but GenericApplicationContext does not support.
ContextStartedEvent Published when ApplicationContext is launched using the start () method on the configurable ApplicationContext interface. Here, “start” means that all lifecycle beans receive an explicit start signal. Typically, this signal is used to restart beans after an explicit stop, but it can also be used to start components that are not configured to start automatically (for example, components that were not started at initialization).
ContextStoppedEvent Published when ApplicationContext is stopped using the stop () method on the configurable ApplicationContext interface. Here, “stop” means that all lifecycle beans receive an explicit stop signal. The stopped context can be restarted with the start () call.
ContextClosedEvent Published when the ApplicationContext is closed using the close () method on the configurable ApplicationContext interface. Here, “closed” means that all singleton Beans have been destroyed. The closed environment reached the end of its life. Unable to refresh or restart.
RequestHandledEvent A Web-specific event that tells all beans that an HTTP request has been served. This event is published after the request completes. This event only applies to Web applications that use Spring’s DispatcherServlet.

Inheritation-based events

You can also customize events. Here is an example that inherits ApplicationEvent:

public class BlackListEvent extends ApplicationEvent {

    private final String address;
    private final String content;

    public BlackListEvent(Object source, String address, String content) {
        super(source);
        this.address = address;
        this.content = content; }}Copy the code

If you want to release the custom ApplicationEvent, calling on ApplicationEventPublisher PublishEvent () method. Usually can be done by implement ApplicationEventPublisherAware interfaces, as shown below:

public class EmailService implements ApplicationEventPublisherAware {

    private List<String> blackList;
    private ApplicationEventPublisher publisher;

    public void setBlackList(List<String> blackList) {
        this.blackList = blackList;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendEmail(String address, String content) {
        if (blackList.contains(address)) {
            publisher.publishEvent(new BlackListEvent(this, address, content));
            return; }}}Copy the code

When configured, detected by the Spring container, realized the EmailService ApplicationEventPublisherAware and automatically call setApplicationEventPublisher (). In fact, the argument passed in is the Spring container itself. You are through its applicationEventPublisher interface to interact with the application context.

To receive a custom applicationEvent, create a class that implements applicationListener and register it as a SpringBean. The following example shows such a class:

public class BlackListNotifier implements ApplicationListener<BlackListEvent> {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    public void onApplicationEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...}}Copy the code

The BlackListEvent generic of ApplicationListener is used. Means that the onApplicationEvent () method keeps type safe, avoiding any need for downward casts.

Note, however, that by default, event listeners receive events synchronously. This means that the publishEvent () method blocks until all listeners have finished processing the event.

Here is an example of registering and configuring beans:

<bean id="emailService" class="example.EmailService">
    <property name="blackList">
        <list>
            <value>[email protected]</value>
            <value>[email protected]</value>
            <value>[email protected]</value>
        </list>
    </property>
</bean>

<bean id="blackListNotifier" class="example.BlackListNotifier">
    <property name="notificationAddress" value="[email protected]"/>
</bean>
Copy the code

Spring’s event mechanism is designed for simple communication between Spring beans within the same application context. More complex enterprise Integration requirements can be addressed using Spring Integration’s AMQP model.

Annotation-based events

Starting with Spring4.2, you can register event listeners on any public method of a managed bean using the EventListener annotation. The BlackListNotifier program can be rewritten as follows:

public class BlackListNotifierAnnotation {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    @EventListener
    public void processBlackListEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...}}Copy the code

If your method should listen for multiple events, or if you want to define it without any parameters, you can also specify the event type on the annotation itself. The following example shows how to do this:

    @EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
    public void handleContextStart(a) {}Copy the code

Additional run-time filters can also be added using the conditional properties of the annotations that define the spEL expression, which should match the method that actually calls the particular event.

The following example shows how to override the notifier so that it is called only when the content attribute of the event is equal to my-Event:

    @EventListener(condition = "#blEvent.content == 'my-event'")
    public void processBlackListSPELEvent(BlackListEvent blEvent) {
        // notify appropriate parties via notificationAddress...
    }
Copy the code

The following table lists the items available in context so that you can use them for conditional event processing:

name Location describe example
Event root object The real ApplicationEvent #root.event
Arguments array root object Parameters to call the target #root.args[0]
Argument name evaluation context The name of any method parameter. If for some reason the name is not available (for example, because there is no debugging information), the parameter name can also be used under #a<#arg>, where #arg represents the parameter index (starting from 0). #p<#arg>

Asynchronous listener

If you want specific listeners to process events asynchronously, you can reuse the regular @async support. Here is an example of @async:

    @Async
    @EventListener
    public void processBlackListEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
Copy the code

Listeners sorting

If you need to call one listener first and then another, you can add the @Order annotation to the method declaration as follows:

    @EventListener
    @Order(12)
    public void processBlackListEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
Copy the code

For an example of this article, see: Event

See flydean’s blog for more tutorials