I do not think @Async and @Scheduled are meant to be used on the same method, even if it does work.
First, a @Scheduled method should return void and have no parameters (for obvious reasons), whereas an @Async method can have parameters and can return a value (i.e. Future<?>
).
Second, @EnableScheduling will look for a TaskScheduler
to execute the @Scheduled methods, whereas @EnableAsync will look for a TaskExecutor
to execute the @Async methods. The two are different things, Spring doc says:
The Spring Framework provides abstractions for the asynchronous execution and scheduling of tasks with the TaskExecutor and TaskScheduler interfaces, respectively.
However, it is possible to use @EnableAsync and @EnableScheduling on the same @Configuration class, depending on what you want to do. For example, the Spring documentation shows this example:
@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {}
It can indeed be a bit confusing at first, but as they mention:
You can pick and choose the relevant annotations for your application. For example, if you need only support for @Scheduled, you can omit @EnableAsync.
The example is probably there if you want to do something like:
@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
@Async // requires @EnableAsync
public Future<String> asyncMethod(String data) {
// do something
return CompletableFuture.completedFuture("finished");
}
@Scheduled(fixedRate = 1_000) // requires @EnableScheduling
public void everySecond() {
// do something
}
}
As for your question, how can the scheduled task run?, the doc for @EnableScheduling says:
By default, Spring will search for an associated scheduler definition: either a unique TaskScheduler bean in the context, or a TaskScheduler bean named "taskScheduler" otherwise; (…). If neither of the two is resolvable, a local single-threaded default scheduler will be created and used within the registrar.
So, if you have multiple @Scheduled methods and want them to be able to execute in parallel, you need to define a TaskScheduler
with a pool size greater than one:
@Configuration
@EnableScheduling
public class SchedulerContext {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("sched-task-");
scheduler.setPoolSize(10); // 1 is the default value
scheduler.initialize();
return scheduler;
}
}