Introduction to the

Spring’s event-driven model is based on ApplicationEvent and ApplicationListener to realize the interaction between business modules in an event-driven manner. There are also synchronous and asynchronous interaction modes. Event publishers are only responsible for publishing events and do not care about event receivers. There may be one or multiple receivers. Similarly, the recipient does not know who is Posting the event. Spring’s event-driven model consists of three parts, the producer of the sending message, the consumer of the message, and the consumer of the event listener, all of which are bound together, similar to RabbitMQ’s message model.

Built-in event

Spring provides built-in events. At the heart of Spring is the ApplicationContext, which releases certain types of events when a Bean is loaded, It is then processed through ApplicationEvent and ApplicationListener.

The serial number The event describe
1 ContextStartedEvent Triggered when the container starts
2 ContextRefreshedEvent Container initialization or refreshApplicationContext, the event will be published
3 ContextStoppedEvent Triggered when the container stops
4 ContextClosedEvent Triggered when the container is closed

Custom events

Create/listen events should follow these guidelines

  • Event classes should inheritApplicationEvent
  • Event publishers should injectApplicationEventPublisher
  • Event listeners should be implementedApplicationListener
  1. Create an event class that inherits ApplicationEvent

    public class CustomSpringEvent extends ApplicationEvent {
    
        private String message;
    
        public CustomSpringEvent(Object source, String message) {
            super(source);
            this.message = message;
        }
    
        public String getMessage(a) {
            returnmessage; }}Copy the code
  2. Create the event publisher ApplicationEventPublisher injection

    @Component
    public class CustomSpringEventPublisher {
       
        @Autowired
        ApplicationEventPublisher applicationEventPublisher;
    
        public void publishCustomEvent(String message) {
            CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
            // Publish eventsapplicationEventPublisher.publishEvent(customSpringEvent); }}Copy the code
  3. The listener that creates the event implements the ApplicationListener interface

    @Component
    public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {
    
        @Override
        public void onApplicationEvent(CustomSpringEvent event) {
            System.out.println("Events received:"+ event.getMessage()); }}Copy the code

Annotation driven

Spring 4.1 provides @eventlister. You don’t need to manually implement the ApplicationListener interface to listen for events. You can also configure @async to use it

public @interface EventListener {

	@AliasFor("classes")Class<? >[] value()default {};

	@AliasFor("value")Class<? >[] classes()default {};

	String condition(a) default "";

}
Copy the code
  • Value: classes alias
  • Classes: You can specify the type of message object to listen on
  • Condition: Specifies that event listening is triggered under the condition that the expression evaluates to true

Event publishing

@Component
public class ApplicationEventPublisher {

    ApplicationContext itself can publish various events
    @Autowired
    ApplicationContext applicationContext;

    public void publish(String message) { applicationContext.publishEvent(message); }}Copy the code

Event listeners

@Component
public class AsyncApplicationEventListener {

    @EventListener(String.class)
    public void listener(String message) throws InterruptedException {
        System.out.println("1- Asynchronous event listening, message:" + message);
    }

    /** * classes can be omitted. By default, events in method arguments are listened for@param message
     * @throws InterruptedException
     */
    @EventListener(condition = "#message.length() > 5")
    public void listener2(String message) throws InterruptedException {
        System.out.println("2- Asynchronous event listening, message:" + message);
    }

    /** * Message is triggered when the length is greater than 50@param message
     * @throws InterruptedException
     */
    @EventListener(condition = "#message.length() > 50")
    public void listener3(String message) throws InterruptedException {
        System.out.println("3- Asynchronous event listening, message:"+ message); }}Copy the code

test

@SpringBootTest(classes = EventApplication.class)
public class AsyncApplicationEventPublisherTest {

    @Autowired
    ApplicationEventPublisher applicationEventPublisher;

    @Test
    public void publishTest(a) throws InterruptedException {
        applicationEventPublisher.publish("Release the news."); System.in.read(); }}Copy the code

Asynchronous events

Events in Spring are synchronous by default, and the publisher thread blocks until all listeners have finished processing the event. If you want the event listener to execute asynchronously, you need to add @async to the listener and @enableAsync annotation to the main startup class

@Component
public class CustomSpringEventListene {

     @Async
    @EventListener(String.class)
    public void listener(String message) throws InterruptedException {
        System.out.println("1- Asynchronous event listening, message:" + message);
    
}
Copy the code

Thread pool configuration is also supported

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean("pool")
    public AsyncTaskExecutor  taskExecutor(a) {
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("consumer-queue-thread-%d").build();
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // The thread pool maintains the minimum number of threads
        executor.setCorePoolSize(5);
        The thread pool maintains the maximum number of threads
        executor.setMaxPoolSize(10);
        // Cache the queue
        executor.setQueueCapacity(25);
        / / thread
        executor.setThreadFactory(namedThreadFactory);
        // Thread pool initialization
        executor.initialize();
        returnexecutor; }}Copy the code
@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {

    @Async("pool")
    @Override
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println("Events received:"+ event.getMessage()); }}Copy the code

Transaction binding event

Transaction binding events @ TransactionalEventListener is an extension of the @ EventListener, Spring allows the event listener is bound to the affairs of a certain stage.

You can bind to the following transaction phases:

  • If the transaction completes successfully, AFTER_COMMIT (the default) is used to trigger the event
  • AFTER_ROLLBACK – If the transaction has been rolled back
  • AFTER_COMPLETION – If the transaction has completed (aliases for AFTER_COMMIT and AFTER_ROLLBACK)
  • BEFORE_COMMIT is used to trigger events immediately before a transaction commits
public @interface TransactionalEventListener {

	TransactionPhase phase(a) default TransactionPhase.AFTER_COMMIT;

    /** * Specifies whether to process the event if there is no transaction running. The default is false
	boolean fallbackExecution(a) default false;

	@AliasFor(annotation = EventListener.class, attribute = "classes")Class<? >[] value()default {};

	@AliasFor(annotation = EventListener.class, attribute = "classes")Class<? >[] classes()default {};

	String condition(a) default "";

}

public enum TransactionPhase {
	BEFORE_COMMIT,
	AFTER_COMMIT,
	AFTER_ROLLBACK,
	AFTER_COMPLETION
}
Copy the code

If the execution of method A requires the result of the completion of method B, but A and B are not in the same transaction, and the transaction in B is not mentioned, A cannot get the data, then we should wait for B to submit the transaction before executing method A.

 @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleCustom(CustomSpringEvent event) {
    System.out.println("Before transaction commit");
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleCustom1(CustomSpringEvent event) {
    System.out.println("Transaction Rollback");
}
Copy the code

conclusion

Spring’s event mechanism enables code decoupling as well as asynchronous event tasks.