头图

[Note] This article is translated from: Spring Events | Baeldung

1 Overview

In this tutorial, we will discuss how to use events in Spring .

Event is one of the most overlooked features in the framework, but it is also one of the more useful features. Like many other things in Spring, event publishing is one of the features provided by the ApplicationContext

There are some simple guidelines to follow:

  • If we use a version earlier than Spring Framework 4.2, the event class should extend ApplicationEvent. from version 4.2 to start , event class no longer needs to be extended the ApplicationEvent class.
  • The publisher should inject a ApplicationEventPublisher object.
  • The listener should implement the ApplicationListener interface.

    2. Custom event

    Spring allows us to create and publish custom events that are synchronized by This has some advantages, such as the ability of the listener to participate in the transaction context of the publisher.

2.1. A simple application event

Let's create a simple event like - just a placeholder for storing event data.

In this case, the event class contains a String message:

public class CustomSpringEvent extends ApplicationEvent {
    private String message;

    public CustomSpringEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

2.2. Publisher

Now let's create publisher of the event . The publisher constructs the event object and publishes it to anyone who is listening.

To publish events, the publisher can simply inject ApplicationEventPublisher and use publishEvent() API:

@Component
public class CustomSpringEventPublisher {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void publishCustomEvent(final String message) {
        System.out.println("Publishing custom event. ");
        CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
        applicationEventPublisher.publishEvent(customSpringEvent);
    }
}

Alternatively, the publisher class can implement
ApplicationEventPublisherAware interface, which will also inject the event publisher when the application starts. Generally, it is inject 1618b27af6a92a @Autowire into the publisher.

Starting from Spring Framework 4.2, the ApplicationEventPublisher interface provides a new overload for the publishEvent(Object event) method, which accepts any object as an event. Therefore, the Spring event no longer needs to extend the ApplicationEvent class .

2.3. Listener

Finally, let's create the listener.

The only requirement for the listener is to be a bean and implement the ApplicationListener interface:

@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {
    @Override
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println("Received spring custom event - " + event.getMessage());
    }
}

Please note how our custom listener is parameterized with the common types of custom events, which makes the onApplicationEvent() method type safe. This also avoids having to check whether the object is an instance of a specific event class and transform it.

And, as already discussed (by default, Spring events are synchronous ), the doStuffAndPublishAnEvent() method will block until all listeners have finished processing the event.

3. Create an asynchronous event

In some cases, publishing events synchronously is not what we really want- We may need to process our events asynchronously.

We can create a
ApplicationEventMulticaster bean Open it in the configuration.

For us, SimpleAsyncTaskExecutor achieves this goal well:

@Configuration
public class AsynchronousSpringEventsConfig {
    @Bean(name = "applicationEventMulticaster")
    public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
        eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return eventMulticaster;
    }
}

The implementation of events, publishers, and listeners are the same as before, but now the listener will process the event asynchronously in a separate thread.

4. Existing frame events

Spring itself publishes various events out of the box. For example, ApplicationContext will trigger various framework events: ContextRefreshedEvent , ContextStartedEvent , RequestHandledEvent and so on.

These events provide an option for application developers to connect to the life cycle and context of the application and add their own custom logic where needed.

This is a quick example of a listener listening for context refresh:

public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent cse) {
        System.out.println("Handling context re-freshed event. ");
    }
}

To learn more about existing framework events, check out our next tutorial .

5. Annotation-driven event listener

Starting from Spring 4.2, the event listener does not need to be a that implements the 1618b27af6accc ApplicationListener interface-it can be on any public method of the managed bean through the 1618b27af6acd3 @EventListener

@Component
public class AnnotationDrivenEventListener {
    @EventListener
    public void handleContextStart(ContextStartedEvent cse) {
        System.out.println("Handling context started event.");
    }
}

As before, the method signature declares the type of event it uses.

By default, the listener is called synchronously. However, we can easily make it asynchronous @Async We just need to remember to enable asynchronous support in the application.

6. Generic support

You can also use the generic information in the event type to schedule events.

6.1. Generic application events

Let's create a generic event type.

In our example, the event class contains any content and success status indicator:

public class GenericSpringEvent<T> {
    private T what;
    protected boolean success;

    public GenericSpringEvent(T what, boolean success) {
        this.what = what;
        this.success = success;
    }
    // ... standard getters
}

Please note the difference between GenericSpringEvent and CustomSpringEvent We can now publish arbitrary events flexibly, and no longer need to extend ApplicationEvent

6.2. Listener

Now let's create a listener for this event.

We can define the listener by implementing the ApplicationListener

@Component
public class GenericSpringEventListener implements ApplicationListener<GenericSpringEvent<String>> {
    @Override
    public void onApplicationEvent(@NonNull GenericSpringEvent<String> event) {
        System.out.println("Received spring generic event - " + event.getWhat());
    }
}

Unfortunately, this definition requires us to inherit GenericSpringEvent ApplicationEvent class. So, for this tutorial, let's use the annotation-driven event listener discussed earlier.

You can also make the event listener conditional by defining a Boolean SpEL expression on the @EventListener

In this case, the event handler will only be called when the String object of GenericSpringEvent

@Component
public class GenericSpringEventListener implements ApplicationListener<GenericSpringEvent<String>> {
    @Override
    public void onApplicationEvent(@NonNull GenericSpringEvent<String> event) {
        System.out.println("Received spring generic event - " + event.getWhat());
    }

}
Spring Expression Language ( ) 1618b27af6afa5 ") is a powerful expression language, detailed in another tutorial.

6.3. Publisher

The event publisher is similar to the above. But due to type erasure, we need to publish an event to parse the generic parameters we will filter, for example, the class GenericStringSpringEvent extends GenericSpringEvent<String> .

In addition, there is an alternative method for publishing events, . If we @EventListener , Spring Framework will send the result to us as a new event. In addition, by returning multiple new events to a collection as the result of event processing, we can publish multiple new events.

7. Transaction binding events

This section is about using *@
TransactionalEventListener* annotated. To learn more about transaction management, see Using Spring and JPA transactions .

Starting from Spring 4.2, the framework provides a new *@
TransactionalEventListener annotation, it is @EventListener*, which allows the event listener to be bound to a certain stage of the transaction.

Can be bound to the following transaction phases:

  • AFTER_COMMIT (default) trigger the event 1618b27af6b133 when the
  • AFTER_ROLLBACK -if transaction has been rolled back
  • AFTER_COMPLETION -If transaction has been completed ( AFTER_COMMIT and AFTER_ROBACK alias)
  • BEFORE_COMMIT - for the transaction before submitting trigger event.

This is a quick example of a transactional event listener:

@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleCustom(CustomSpringEvent event) {
    System.out.println("Handling event inside a transaction BEFORE COMMIT.");
}

This listener will only be called when there is a transaction that the event producer is running and is about to commit.

If no transaction is running, the event will not be sent at all, unless we override it fallbackExecution property to true

8. Conclusion

In this short article, we introduced the of handling event in 1618b27af6b2f4 Spring, including creating a simple custom event, publishing it, and then processing it in the listener.

We also briefly learned how to enable asynchronous processing of events in the configuration.

Then we learned about the improvements introduced in Spring 4.2, such as annotation-driven listeners, better generic support, and event binding to the transaction phase.

As usual, the code provided herein may on GitHub obtained. This is a Maven-based project, so it should be easy to import and run.


信码由缰
65 声望8 粉丝

“码”界老兵,分享程序人生。