Learning is endless, and you are encouraged.

scenario

Most of the time, when we complete some business, we need to push relevant message reminders to users. For this non-core business function we can take it out and create an event to execute asynchronously to decouple the core business from the sub-business.

implementation

Define the Event class Event

Create a class that inherits ApplicationEvent and overwrites the constructor. ApplicationEvent is an extension class for all application events provided by Spring.

public class NoticeEvent extends ApplicationEvent {



    private static final Logger logger = LoggerFactory.getLogger(NoticeEvent.class);



    / * *

* Receive information

* /


    private String message;



    public NoticeEvent(String message) {

        super(message);

        this.message = message;

        logger.info("add event success! message: {}", message);

    }



    public String getMessage(a) {

        return message;

    }

}

Copy the code

Create an event Listener class

To create a class that listens for specified events, implement the ApplicationListener interface, stating that it is a listener class for application events. Note that you need to inject the @Component annotation into the Spring container.

@Component

public class NoticeListener implements ApplicationListener<NoticeEvent{



    private static final Logger logger = LoggerFactory.getLogger(NoticeListener.class);



    @Override

    public void onApplicationEvent(NoticeEvent noticeEvent) {

        logger.info("listener get event, sleep 2 second...");

        try {

            Thread.sleep(2000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        logger.info("event message is : {}", noticeEvent.getMessage());

    }

}

Copy the code

Event publishing

Event publishing is very simple, only need to use the Spring provided ApplicationEventPublisher to distribute custom events

@RestController

@RequestMapping("/event")

public class EventController {



    private static final Logger logger = LoggerFactory.getLogger(EventController.class);



    @Autowired

    private ApplicationEventPublisher applicationEventPublisher;



    @GetMapping("/notice/{message}")

    public void notice(@PathVariable(name = "message") String message) {

        logger.info("begin >>>>>>");

        applicationEventPublisher.publishEvent(new NoticeEvent(message));

        logger.info("end <<<<<<");

    }

}

Copy the code

test

Start the service, http://localhost:8080/event/notice/hello access interface

[nio-8080-exec-1] o.y.n.event.controller.EventController   : begin >>>>>>

[nio-8080-exec-1] org.ylc.note.event.event.NoticeEvent     : add event success! message: hello

[nio-8080-exec-1] org.ylc.note.event.event.NoticeListener  : listener get event, sleep 2 second...

[nio-8080-exec-1] org.ylc.note.event.event.NoticeListener  : event message is : hello

[nio-8080-exec-1] o.y.n.event.controller.EventController   : end <<<<<<

Copy the code

The execution was successful, but no asynchronous execution was found by console printing

Asynchronous execution

Asynchrony is not enabled by default, so we need to manually configure asynchrony to be enabled. Simply add @enableAsync annotation to the Configuration class. This annotation is used to declare that Spring’s asynchronous method execution function is enabled. Then add an @async annotation to the listener method to indicate that the current method is being executed asynchronously.

    @Async

    @Override

    public void onApplicationEvent(NoticeEvent noticeEvent) {

        logger.info("listener get event, sleep 2 second...");

        try {

            Thread.sleep(2000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        logger.info("event message is : {}", noticeEvent.getMessage());

    }

Copy the code

Restart the service and re-access the interface:

[nio-8080-exec-1] o.y.n.event.controller.EventController   : begin >>>>>>

[nio-8080-exec-1] org.ylc.note.event.event.NoticeEvent     : add event success! message: hello

[nio-8080-exec-1] o.y.n.event.controller.EventController   : end <<<<<<

[         task-1] org.ylc.note.event.event.NoticeListener  : listener get event, sleep 2 second...

[         task-1] org.ylc.note.event.event.NoticeListener  : event message is : hello

Copy the code

The main thread is NIO-8080-EXEC-1, and the listening thread is task-1. As you can see from the browser response, the interface returns directly, without waiting for the listener thread to finish executing.

Custom asynchronous thread pool

When asynchrony is enabled, Spring’s internal default thread pool is used, which we can customize. Create a Configuration class (plus @Configuration) that implements the AsyncConfigurer interface and overrides the Executor method. Here we can place the @EnableAsync annotation that was previously configured on the launch class on this class.

@Configuration

@EnableAsync

public class AsyncConfig implements AsyncConfigurer {



    private final Logger log = LoggerFactory.getLogger(this.getClass());



    / * *

* Custom asynchronous thread pool, if not overridden will use the default thread pool

* /


    @Override

    public Executor getAsyncExecutor(a) {

        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();

        // Number of core threads

        taskExecutor.setCorePoolSize(2);

        // Maximum number of threads

        taskExecutor.setMaxPoolSize(10);

        // Queue size

        taskExecutor.setQueueCapacity(15);

        // Prefix of thread name

        taskExecutor.setThreadNamePrefix("async-thread-");

        taskExecutor.initialize();

        return taskExecutor;

    }



    / * *

Catch the IllegalArgumentException exception

* /


    @Override

    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler(a) {

        return new MyAsyncExceptionHandler();

    }



    class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

        @Override

        public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {

            log.info("TASK Exception message - " + throwable.getMessage());

            log.info("Method name - " + method.getName());

            for (Object param : objects) {

                log.info("Parameter value - " + param);

            }

        }

    }

}

Copy the code

Restart the service and re-access the interface:

[nio-8080-exec-1] o.y.n.event.controller.EventController   : begin >>>>>>

[nio-8080-exec-1] org.ylc.note.event.event.NoticeEvent     : add event success! message: hello

[nio-8080-exec-1] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService

[nio-8080-exec-1] o.y.n.event.controller.EventController   : end <<<<<<

[ async-thread-1] org.ylc.note.event.event.NoticeListener  : listener get event, sleep 2 second...

[ async-thread-1] org.ylc.note.event.event.NoticeListener  : event message is : hello

Copy the code

If the name of the asynchronous thread in the console is changed to async-thread-x, the configuration is successful.

Access to the source code

All codes are uploaded to Github for easy access

>>>>>> event Event <<<<<<

Daily for praise

Creation is not easy, if you feel helpful, please support

Please focus on