Spring Boot AutoConfigure provides auto-configuration capabilities that automatically configure Spring applications based on jar dependencies present on the classpath
—
Spring Boot AutoConfigure provides configuration properties for task execution and scheduling, allowing fine-grained control over thread pools, concurrency limits, and shutdown behavior for asynchronous task processing and scheduled tasks.
import org.springframework.boot.autoconfigure.task.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;Configuration properties for task execution with support for both simple and pool-based executors.
@ConfigurationProperties("spring.task.execution")
public class TaskExecutionProperties {
/**
* Get simple executor configuration.
*/
public Simple getSimple();
/**
* Get pool executor configuration.
*/
public Pool getPool();
/**
* Get shutdown configuration.
*/
public Shutdown getShutdown();
/**
* Determine when the task executor is to be created.
* Default is AUTO (create only if no user-defined executor present).
*/
public Mode getMode();
public void setMode(Mode mode);
/**
* Prefix to use for the names of newly created threads.
* Default is "task-".
*/
public String getThreadNamePrefix();
public void setThreadNamePrefix(String threadNamePrefix);
/**
* Simple executor configuration for lightweight concurrency control.
*/
public static class Simple {
/**
* Whether to cancel remaining tasks on close.
* Only recommended if threads are commonly expected to be stuck.
* Default is false.
*/
public boolean isCancelRemainingTasksOnClose();
public void setCancelRemainingTasksOnClose(boolean cancelRemainingTasksOnClose);
/**
* Whether to reject tasks when the concurrency limit has been reached.
* Default is false.
*/
public boolean isRejectTasksWhenLimitReached();
public void setRejectTasksWhenLimitReached(boolean rejectTasksWhenLimitReached);
/**
* Set the maximum number of parallel accesses allowed.
* -1 indicates no concurrency limit at all.
* Null means no limit is set.
*/
public Integer getConcurrencyLimit();
public void setConcurrencyLimit(Integer concurrencyLimit);
}
/**
* Pool executor configuration for ThreadPoolTaskExecutor.
*/
public static class Pool {
/**
* Queue capacity for pending tasks.
* An unbounded capacity does not increase the pool and therefore ignores max-size.
* Doesn't have an effect if virtual threads are enabled.
* Default is Integer.MAX_VALUE (unbounded).
*/
public int getQueueCapacity();
public void setQueueCapacity(int queueCapacity);
/**
* Core number of threads in the pool.
* Doesn't have an effect if virtual threads are enabled.
* Default is 8.
*/
public int getCoreSize();
public void setCoreSize(int coreSize);
/**
* Maximum allowed number of threads.
* If tasks are filling up the queue, the pool can expand up to this size.
* Ignored if the queue is unbounded.
* Doesn't have an effect if virtual threads are enabled.
* Default is Integer.MAX_VALUE.
*/
public int getMaxSize();
public void setMaxSize(int maxSize);
/**
* Whether core threads are allowed to time out.
* This enables dynamic growing and shrinking of the pool.
* Doesn't have an effect if virtual threads are enabled.
* Default is true.
*/
public boolean isAllowCoreThreadTimeout();
public void setAllowCoreThreadTimeout(boolean allowCoreThreadTimeout);
/**
* Time limit for which threads may remain idle before being terminated.
* Doesn't have an effect if virtual threads are enabled.
* Default is 60 seconds.
*/
public Duration getKeepAlive();
public void setKeepAlive(Duration keepAlive);
/**
* Get shutdown configuration for the pool.
*/
public Shutdown getShutdown();
public static class Shutdown {
/**
* Whether to accept further tasks after the application context close phase has begun.
* Default is false.
*/
public boolean isAcceptTasksAfterContextClose();
public void setAcceptTasksAfterContextClose(boolean acceptTasksAfterContextClose);
}
}
/**
* Shutdown configuration for task executor.
*/
public static class Shutdown {
/**
* Whether the executor should wait for scheduled tasks to complete on shutdown.
* Default is false.
*/
public boolean isAwaitTermination();
public void setAwaitTermination(boolean awaitTermination);
/**
* Maximum time the executor should wait for remaining tasks to complete.
* Null means wait indefinitely.
*/
public Duration getAwaitTerminationPeriod();
public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod);
}
/**
* Mode determining when the task executor is to be created.
*/
public enum Mode {
/**
* Create the task executor if no user-defined executor is present.
*/
AUTO,
/**
* Create the task executor even if a user-defined executor is present.
*/
FORCE
}
}spring:
task:
execution:
mode: auto
thread-name-prefix: "app-task-"
pool:
core-size: 4
max-size: 16
queue-capacity: 100
keep-alive: 30s
allow-core-thread-timeout: true
shutdown:
accept-tasks-after-context-close: false
shutdown:
await-termination: true
await-termination-period: 60sConfiguration properties for task scheduling with ThreadPoolTaskScheduler.
@ConfigurationProperties("spring.task.scheduling")
public class TaskSchedulingProperties {
/**
* Get pool configuration.
*/
public Pool getPool();
/**
* Get simple configuration.
*/
public Simple getSimple();
/**
* Get shutdown configuration.
*/
public Shutdown getShutdown();
/**
* Prefix to use for the names of newly created threads.
* Default is "scheduling-".
*/
public String getThreadNamePrefix();
public void setThreadNamePrefix(String threadNamePrefix);
/**
* Pool configuration for scheduled task executor.
*/
public static class Pool {
/**
* Maximum allowed number of threads.
* Doesn't have an effect if virtual threads are enabled.
* Default is 1.
*/
public int getSize();
public void setSize(int size);
}
/**
* Simple configuration for lightweight scheduled task execution.
*/
public static class Simple {
/**
* Set the maximum number of parallel accesses allowed.
* -1 indicates no concurrency limit at all.
* Null means no limit is set.
*/
public Integer getConcurrencyLimit();
public void setConcurrencyLimit(Integer concurrencyLimit);
}
/**
* Shutdown configuration for task scheduler.
*/
public static class Shutdown {
/**
* Whether the executor should wait for scheduled tasks to complete on shutdown.
* Default is false.
*/
public boolean isAwaitTermination();
public void setAwaitTermination(boolean awaitTermination);
/**
* Maximum time the executor should wait for remaining tasks to complete.
* Null means wait indefinitely.
*/
public Duration getAwaitTerminationPeriod();
public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod);
}
}spring:
task:
scheduling:
thread-name-prefix: "scheduler-"
pool:
size: 2
shutdown:
await-termination: true
await-termination-period: 30simport org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAsync
public class AsyncConfiguration {
// Async support enabled
}
@Service
public class EmailService {
@Async
public void sendEmail(String to, String subject, String body) {
// This method runs asynchronously in the configured task executor
System.out.println("Sending email to " + to + " in thread: " +
Thread.currentThread().getName());
// Email sending logic
}
@Async
public CompletableFuture<String> processWithResult() {
// Async method that returns a result
String result = performLongRunningTask();
return CompletableFuture.completedFuture(result);
}
private String performLongRunningTask() {
// Long-running task logic
return "Task completed";
}
}import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableScheduling
public class SchedulingConfiguration {
// Scheduling support enabled
}
@Component
public class ScheduledTasks {
@Scheduled(fixedRate = 5000)
public void performTask() {
System.out.println("Task executed every 5 seconds in thread: " +
Thread.currentThread().getName());
}
@Scheduled(cron = "0 0 * * * *")
public void hourlyTask() {
System.out.println("Hourly task executed");
}
@Scheduled(fixedDelay = 10000, initialDelay = 5000)
public void delayedTask() {
System.out.println("Task with fixed delay and initial delay");
}
}import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.concurrent.Executor;
@Configuration
public class TaskConfiguration {
@Bean(name = "customTaskExecutor")
public Executor customTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(50);
executor.setThreadNamePrefix("custom-exec-");
executor.initialize();
return executor;
}
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(3);
scheduler.setThreadNamePrefix("custom-scheduler-");
scheduler.setWaitForTasksToCompleteOnShutdown(true);
scheduler.setAwaitTerminationSeconds(30);
scheduler.initialize();
return scheduler;
}
}
@Service
public class ServiceWithCustomExecutor {
@Async("customTaskExecutor")
public void executeWithCustomExecutor() {
System.out.println("Running in custom executor: " +
Thread.currentThread().getName());
}
}spring:
task:
execution:
# Execution mode
mode: auto # or 'force' to create even if user-defined executor exists
# Thread naming
thread-name-prefix: "myapp-task-"
# Simple executor settings (lightweight alternative)
simple:
concurrency-limit: 10
cancel-remaining-tasks-on-close: false
reject-tasks-when-limit-reached: true
# Pool executor settings (default executor type)
pool:
core-size: 8
max-size: 32
queue-capacity: 1000
keep-alive: 60s
allow-core-thread-timeout: true
shutdown:
accept-tasks-after-context-close: false
# Shutdown behavior
shutdown:
await-termination: true
await-termination-period: 120s
scheduling:
# Thread naming
thread-name-prefix: "myapp-scheduler-"
# Pool settings
pool:
size: 4
# Simple settings (alternative to pool)
simple:
concurrency-limit: 5
# Shutdown behavior
shutdown:
await-termination: true
await-termination-period: 60sspring:
task:
execution:
pool:
core-size: 16
max-size: 64
queue-capacity: 500
keep-alive: 120s
shutdown:
await-termination: true
await-termination-period: 180s
scheduling:
pool:
size: 8
shutdown:
await-termination: true
await-termination-period: 90sspring:
task:
execution:
pool:
core-size: 2
max-size: 4
queue-capacity: 10
shutdown:
await-termination: true
await-termination-period: 5s
scheduling:
pool:
size: 1
shutdown:
await-termination: true
await-termination-period: 5simport org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import java.util.concurrent.Executor;
@Configuration
public class AsyncExceptionHandlingConfiguration implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, params) -> {
System.err.println("Exception in async method: " + method.getName());
System.err.println("Exception message: " + throwable.getMessage());
};
}
}
@Service
public class RobustTaskService {
private static final Logger logger = LoggerFactory.getLogger(RobustTaskService.class);
@Async
public void executeWithErrorHandling() {
try {
// Task logic that might throw exceptions
performRiskyOperation();
} catch (Exception e) {
logger.error("Error in async task", e);
// Handle or rethrow
}
}
@Scheduled(fixedRate = 60000)
public void scheduledTaskWithErrorHandling() {
try {
// Scheduled task logic
performScheduledOperation();
} catch (Exception e) {
logger.error("Error in scheduled task", e);
// Continue running on next schedule
}
}
private void performRiskyOperation() {
// Implementation
}
private void performScheduledOperation() {
// Implementation
}
}import org.springframework.boot.actuate.metrics.AutoTimer;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
@Service
public class MonitoredTaskService {
private final MeterRegistry meterRegistry;
private final Timer taskTimer;
public MonitoredTaskService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.taskTimer = Timer.builder("async.task.execution")
.description("Async task execution time")
.register(meterRegistry);
}
@Async
public void monitoredTask() {
taskTimer.record(() -> {
// Task execution
performWork();
});
}
private void performWork() {
// Implementation
}
}# For CPU-bound tasks
spring:
task:
execution:
pool:
core-size: ${NUMBER_OF_PROCESSORS} # Match CPU cores
max-size: ${NUMBER_OF_PROCESSORS}
queue-capacity: 100
# For I/O-bound tasks
spring:
task:
execution:
pool:
core-size: ${NUMBER_OF_PROCESSORS * 2}
max-size: ${NUMBER_OF_PROCESSORS * 4}
queue-capacity: 500spring:
task:
execution:
shutdown:
await-termination: true
await-termination-period: 120s # Allow time for tasks to complete
scheduling:
shutdown:
await-termination: true
await-termination-period: 60s# application-dev.yml
spring:
task:
execution:
pool:
core-size: 2
max-size: 4
# application-prod.yml
spring:
task:
execution:
pool:
core-size: 16
max-size: 64