#spring #spring-boot #netty #startup #autostart
#spring #spring-boot #netty #запуск #автозапуск
Вопрос:
Я должен запустить несколько методов при запуске приложения, например, следующее:
@SpringBootApplication
public class Application implements CommandLineRunner {
private final MonitoringService monitoringService;
private final QrReaderServer qrReaderServer;
@Override
public void run(String... args) {
monitoringService.launchMonitoring();
qrReaderServer.launchServer();
}
Однако выполняется только первый! И приложение запускается:
... Started Application in 5.21 seconds (JVM running for 6.336)
... START_MONITORING for folder: D:results
Второй всегда пропускается!
Если изменить порядок вызовов — будет выполнен только второй.
Не удалось найти никакого решения для запуска обоих в начале — попробовал @PostConstruct
, ApplicationRunner
@EventListener(ApplicationReadyEvent.class)
…
Похоже, они каким-то образом блокируют друг друга. Несмотря на то, что оба имеют тип void.
Мониторинг реализации запуска:
@Override
public void launchMonitoring() {
log.info("START_MONITORING for folder: {}", monitoringProperties.getFolder());
try {
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == ENTRY_CREATE) {
log.info("FILE_CREATED: {}", event.context());
// some delay for fully file upload
Thread.sleep(monitoringProperties.getFrequency());
String fullFileName = getFileName(event);
String fileName = FilenameUtils.removeExtension(fullFileName);
processResource(fullFileName, fileName);
}
}
key.reset();
}
} catch (InterruptedException e) {
log.error("interrupted exception for monitoring service", e);
} catch (IOException e) {
log.error("io exception while processing file", e);
}
}
Запуск QR Reader (запуск TCP-сервера с конфигурацией Netty):
@Override
public void launchServer() {
try {
ChannelFuture serverChannelFuture = serverBootstrap.bind(hostAddress).sync();
log.info("Server is STARTED : port {}", hostAddress.getPort());
serverChannel = serverChannelFuture.channel().closeFuture().sync().channel();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
shutdownQuietly();
}
}
Как решить эту проблему?
Ответ №1:
Запуск launchMonitoring()
асинхронно.
Самый простой способ сделать это — включить асинхронность, добавив @EnableAsync
в ваше приложение, а затем аннотировать launchMonitoring()
с помощью @Async
Не уверен, что launchServer()
следует также запускать асинхронно.
РЕДАКТИРОВАТЬ: завершенный ответ
No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
По умолчанию Spring создаст SimpleAsyncTaskExecutor
, но вы можете предоставить свой TaskExecutor
Пример:
@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.set... // your custom configs
executor.initialize();
return executor;
}
...
}
Комментарии:
1. make only
launchMonitoring()
— и это работает как очаровательный2. Обнаружен какой-то странный сбой в журнале
No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
. Нужно ли мне добавить какой-либо исполнитель задачи? Пока все работает нормально.3. @nazar_art завершите мой ответ
4. Я установил имя потока для
AsyncConfig
—carpark-ex-1
4 начальных потоков. И посмотрите, что это всегда выполняется только с одним потокомcarpark-ex-1
. Нужно ли мне создавать этот компонент с областью прототипа для выполнения с несколькими потоками?5. почему вы должны хотеть выполняться
launchMonitoring()
с несколькими потоками?