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