учиться никто конец территория , и июнь общий нежелание .
Сцены
Много раз, когда мы завершаем определенные дела, нам нужно отправлять пользователям соответствующие напоминания о сообщениях. Для этой неосновной бизнес-функции мы можем выделить ее и создать событие для ее асинхронного выполнения, тем самым реализовав разделение основного бизнеса и подбизнеса.
выполнить
Определите класс событий Event
Создайте класс, наследуйтеApplicationEvent
и переопределить конструктор.ApplicationEvent
— это класс расширения для всех событий приложения, предоставляемых Spring.
public class NoticeEvent extends ApplicationEvent {
private static final Logger logger = LoggerFactory.getLogger(NoticeEvent.class);
/**
* 接受信息
*/
private String message;
public NoticeEvent(String message) {
super(message);
this.message = message;
logger.info("add event success! message: {}", message);
}
public String getMessage() {
return message;
}
}
Создайте класс прослушивателя событий Listener
Создайте класс для прослушивания указанных событий, которые необходимо реализоватьApplicationListener
Интерфейс, указывающий, что это класс прослушивателя событий приложения. Обратите внимание, что необходимо добавить@Component
Аннотация для внедрения в контейнер Spring.
@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());
}
}
выпуск события
Публикация событий очень проста, нужно только использовать Spring.ApplicationEventPublisher
публиковать пользовательские события
@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 <<<<<<");
}
}
контрольная работа
Запустите службу и получите доступ к интерфейсу http://localhost:8080/event/notice/hello
[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 <<<<<<
Выполнение проходит успешно, но через консольную печать информации обнаруживается, что здесь нет асинхронного выполнения
Асинхронное выполнение
По умолчанию асинхронность не включена, нам нужно вручную настроить асинхронную функцию, это очень просто.класс конфигурациидобавить@EnableAsync
Просто аннотация, эта аннотация используется для объявления выполнения асинхронного метода с поддержкой Spring, который необходимо сопоставить с@Configuration
При использовании вместе с аннотациями мы можем напрямую добавить его встартовый классначальство. Затем добавьте метод слушателя@Async
Аннотация, указывающая, что текущий метод выполняется асинхронно.
@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());
}
Перезапустите службу и повторно получите доступ к интерфейсу:
[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
Можно обнаружить, что реализована асинхронная функция, основной поток — nio-8080-exec-1, прослушивающий поток — задача-1. Из ответа браузера видно, что интерфейс возвращается напрямую и не возвращается после выполнения прослушивающего потока.
Пользовательский пул асинхронных потоков
После включения асинхронности будет использоваться пул потоков по умолчанию в Spring, и мы можем настроить этот пул потоков. Создайте класс конфигурации (плюс@Configuration
),выполнитьAsyncConfigurer
интерфейс, переопределениеExecutor
метод. Здесь мы можем настроить исходную конфигурацию в классе запуска.@EnableAsync
Аннотации выпущены в этом классе.
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* 自定义异步线程池,若不重写会使用默认的线程池
*/
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 核心线程数
taskExecutor.setCorePoolSize(2);
// 最大线程数
taskExecutor.setMaxPoolSize(10);
// 队列大小
taskExecutor.setQueueCapacity(15);
// 线程名的前缀
taskExecutor.setThreadNamePrefix("async-thread-");
taskExecutor.initialize();
return taskExecutor;
}
/**
* 捕捉IllegalArgumentException异常
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
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);
}
}
}
}
Перезапустите службу и повторно получите доступ к интерфейсу:
[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
Имя асинхронного потока в консоли становится определенным нами async-thread-X, что указывает на то, что конфигурация выполнена успешно.
Доступ к исходному коду
Весь код загружен на Github для быстрого доступа
ежедневные комплименты
Это не легко создать, если вы найдете это полезным,попросить лайкслужба поддержки