Spring Framework Core - IoC Container and Dependency Injection
—
Spring Core provides a comprehensive task execution framework that abstracts thread management and provides both synchronous and asynchronous task execution capabilities. This system supports everything from simple thread pools to modern virtual thread implementations.
The task execution system is built around a hierarchy of interfaces that provide increasingly sophisticated execution capabilities.
TaskExecutor Interface
@FunctionalInterface
public interface TaskExecutor extends Executor {
void execute(Runnable task);
}
public interface AsyncTaskExecutor extends TaskExecutor {
long TIMEOUT_UNLIMITED = Long.MAX_VALUE;
long TIMEOUT_IMMEDIATE = 0;
void execute(Runnable task, long startTimeout);
Future<?> submit(Runnable task);
<T> Future<T> submit(Callable<T> task);
}
public interface SchedulingTaskExecutor extends AsyncTaskExecutor {
boolean prefersShortLivedTasks();
}Task Decorator Interface
@FunctionalInterface
public interface TaskDecorator {
Runnable decorate(Runnable runnable);
}Usage Examples
// Basic task execution
TaskExecutor executor = new SimpleAsyncTaskExecutor();
// Execute fire-and-forget tasks
executor.execute(() -> {
System.out.println("Task executed in: " + Thread.currentThread().getName());
});
// Asynchronous execution with results
AsyncTaskExecutor asyncExecutor = new SimpleAsyncTaskExecutor();
// Submit runnable task
Future<?> future1 = asyncExecutor.submit(() -> {
// Long running task
processLargeDataset();
});
// Submit callable task
Future<String> future2 = asyncExecutor.submit(() -> {
return fetchDataFromRemoteService();
});
// Wait for results
try {
future1.get(5, TimeUnit.SECONDS);
String result = future2.get(10, TimeUnit.SECONDS);
} catch (TimeoutException ex) {
// Handle timeout
}
// Task decoration
TaskDecorator decorator = task -> {
return () -> {
String originalName = Thread.currentThread().getName();
Thread.currentThread().setName("CustomTask-" + originalName);
try {
task.run();
} finally {
Thread.currentThread().setName(originalName);
}
};
};
// Apply decorator to executor (implementation-dependent)Spring provides several built-in task executor implementations for different use cases.
SimpleAsyncTaskExecutor
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
implements AsyncTaskExecutor, Serializable {
public static final int UNBOUNDED_CONCURRENCY = -1;
public static final int NO_CONCURRENCY = 0;
public SimpleAsyncTaskExecutor();
public SimpleAsyncTaskExecutor(String threadNamePrefix);
public SimpleAsyncTaskExecutor(ThreadFactory threadFactory);
public void setConcurrencyLimit(int concurrencyLimit);
public int getConcurrencyLimit();
public boolean isThrottleActive();
public void setTaskDecorator(TaskDecorator taskDecorator);
@Override
public void execute(Runnable task);
@Override
public void execute(Runnable task, long startTimeout);
@Override
public Future<?> submit(Runnable task);
@Override
public <T> Future<T> submit(Callable<T> task);
protected void doExecute(Runnable task);
protected Thread createThread(Runnable runnable);
}SyncTaskExecutor
public class SyncTaskExecutor implements TaskExecutor, Serializable {
@Override
public void execute(Runnable task);
}VirtualThreadTaskExecutor (Java 21+)
public class VirtualThreadTaskExecutor implements AsyncTaskExecutor, Serializable {
public VirtualThreadTaskExecutor();
public VirtualThreadTaskExecutor(String threadNamePrefix);
public void setThreadNamePrefix(String threadNamePrefix);
public String getThreadNamePrefix();
public void setTaskDecorator(TaskDecorator taskDecorator);
public TaskDecorator getTaskDecorator();
@Override
public void execute(Runnable task);
@Override
public Future<?> submit(Runnable task);
@Override
public <T> Future<T> submit(Callable<T> task);
@Override
public void execute(Runnable task, long startTimeout);
protected Thread createVirtualThread(Runnable runnable);
}Usage Examples
// Simple async task executor with concurrency control
SimpleAsyncTaskExecutor simpleExecutor = new SimpleAsyncTaskExecutor("MyApp-");
simpleExecutor.setConcurrencyLimit(10); // Limit to 10 concurrent threads
simpleExecutor.setTaskDecorator(task -> {
return () -> {
long start = System.currentTimeMillis();
try {
task.run();
} finally {
long duration = System.currentTimeMillis() - start;
System.out.println("Task completed in " + duration + "ms");
}
};
});
// Execute multiple tasks
for (int i = 0; i < 20; i++) {
final int taskId = i;
simpleExecutor.execute(() -> {
System.out.println("Executing task " + taskId +
" in thread " + Thread.currentThread().getName());
// Simulate work
try { Thread.sleep(1000); } catch (InterruptedException e) {}
});
}
// Synchronous executor (for testing or single-threaded contexts)
TaskExecutor syncExecutor = new SyncTaskExecutor();
syncExecutor.execute(() -> {
// This will execute in the calling thread
System.out.println("Sync execution in: " + Thread.currentThread().getName());
});
// Virtual thread executor (Java 21+)
VirtualThreadTaskExecutor virtualExecutor = new VirtualThreadTaskExecutor("VirtualTask-");
virtualExecutor.setTaskDecorator(task -> () -> {
System.out.println("Virtual thread: " + Thread.currentThread());
task.run();
});
// Virtual threads are ideal for I/O-bound tasks
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 10000; i++) { // Can handle thousands of virtual threads
Future<String> future = virtualExecutor.submit(() -> {
// Simulate I/O operation
Thread.sleep(Duration.ofSeconds(1));
return "Result from virtual thread";
});
futures.add(future);
}
// Collect results
List<String> results = futures.stream()
.map(future -> {
try { return future.get(); }
catch (Exception e) { return "Error"; }
})
.collect(Collectors.toList());While the core module doesn't include full thread pool implementations, it provides the foundation interfaces that are used by Spring's thread pool executors in other modules.
Lifecycle Management
public interface DisposableBean {
void destroy() throws Exception;
}
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
// Task executors often implement these for proper lifecycle management
public interface TaskExecutorConfiguration {
void initialize();
void shutdown();
boolean awaitTermination(long timeout, TimeUnit unit);
}Usage Examples
// Custom task executor with lifecycle management
public class ManagedTaskExecutor implements AsyncTaskExecutor, InitializingBean, DisposableBean {
private ExecutorService executor;
private final String threadNamePrefix;
private TaskDecorator taskDecorator;
public ManagedTaskExecutor(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
}
@Override
public void afterPropertiesSet() {
ThreadFactory threadFactory = new CustomizableThreadFactory(threadNamePrefix);
this.executor = Executors.newCachedThreadPool(threadFactory);
}
@Override
public void destroy() throws Exception {
if (executor != null) {
executor.shutdown();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
}
}
@Override
public void execute(Runnable task) {
Runnable decoratedTask = (taskDecorator != null) ? taskDecorator.decorate(task) : task;
executor.execute(decoratedTask);
}
@Override
public Future<?> submit(Runnable task) {
Runnable decoratedTask = (taskDecorator != null) ? taskDecorator.decorate(task) : task;
return executor.submit(decoratedTask);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return executor.submit(task);
}
public void setTaskDecorator(TaskDecorator taskDecorator) {
this.taskDecorator = taskDecorator;
}
}
// Usage with Spring lifecycle
ManagedTaskExecutor managedExecutor = new ManagedTaskExecutor("Managed-");
managedExecutor.setTaskDecorator(task -> {
return () -> {
MDC.put("taskId", UUID.randomUUID().toString());
try {
task.run();
} finally {
MDC.clear();
}
};
});
managedExecutor.afterPropertiesSet(); // Initialize
// Use the executor
Future<String> result = managedExecutor.submit(() -> {
// Task execution with proper logging context
return "Task completed";
});
// Cleanup
managedExecutor.destroy();CustomizableThreadCreator
public class CustomizableThreadCreator implements Serializable {
public static final String DEFAULT_THREAD_NAME_PREFIX =
ClassUtils.getShortName(CustomizableThreadCreator.class) + "-";
private String threadNamePrefix = DEFAULT_THREAD_NAME_PREFIX;
private int threadPriority = Thread.NORM_PRIORITY;
private boolean daemon = false;
private ThreadGroup threadGroup;
private Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
public CustomizableThreadCreator();
public CustomizableThreadCreator(String threadNamePrefix);
public void setThreadNamePrefix(String threadNamePrefix);
public String getThreadNamePrefix();
public void setThreadPriority(int threadPriority);
public int getThreadPriority();
public void setDaemon(boolean daemon);
public boolean isDaemon();
public void setThreadGroupName(String name);
public void setThreadGroup(ThreadGroup threadGroup);
public ThreadGroup getThreadGroup();
public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler uncaughtExceptionHandler);
public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
public Thread createThread(Runnable runnable);
protected String nextThreadName();
public String getDefaultThreadNamePrefix();
}Usage Examples
// Customizable thread creation
CustomizableThreadCreator threadCreator = new CustomizableThreadCreator("WorkerPool-");
threadCreator.setThreadPriority(Thread.MAX_PRIORITY);
threadCreator.setDaemon(true);
threadCreator.setUncaughtExceptionHandler((thread, ex) -> {
System.err.println("Uncaught exception in thread " + thread.getName() + ": " + ex);
});
// Create custom threads
Thread workerThread = threadCreator.createThread(() -> {
// Worker task implementation
performWork();
});
workerThread.start();
// Use with task executors
public class CustomThreadTaskExecutor extends SimpleAsyncTaskExecutor {
public CustomThreadTaskExecutor() {
super("CustomTask-");
setThreadPriority(Thread.HIGH_PRIORITY);
setDaemon(false);
}
@Override
protected Thread createThread(Runnable runnable) {
Thread thread = super.createThread(runnable);
thread.setUncaughtExceptionHandler((t, e) -> {
// Custom exception handling
handleTaskException(t, e);
});
return thread;
}
private void handleTaskException(Thread thread, Throwable exception) {
// Log exception, notify monitoring system, etc.
}
}While async method execution is handled in Spring Context, the core module provides the foundational interfaces.
Future Result Handling
// Standard JDK interfaces that task executors work with
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
public interface Callable<V> {
V call() throws Exception;
}
// Spring's ListenableFuture (from spring-context) extends this foundationUsage Examples
// Working with Future results
AsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
// Submit tasks and handle results
Future<Integer> calculation = executor.submit(() -> {
// Expensive calculation
Thread.sleep(2000);
return 42;
});
Future<String> dataFetch = executor.submit(() -> {
// Data fetching operation
return fetchFromDatabase();
});
// Non-blocking check
if (calculation.isDone()) {
try {
Integer result = calculation.get();
System.out.println("Calculation result: " + result);
} catch (ExecutionException ex) {
System.err.println("Calculation failed: " + ex.getCause());
}
}
// Blocking wait with timeout
try {
String data = dataFetch.get(5, TimeUnit.SECONDS);
processData(data);
} catch (TimeoutException ex) {
System.err.println("Data fetch timed out");
dataFetch.cancel(true);
} catch (ExecutionException ex) {
System.err.println("Data fetch failed: " + ex.getCause());
}
// Batch processing with CompletableFuture composition
List<Future<String>> futures = IntStream.range(0, 10)
.mapToObj(i -> executor.submit(() -> processItem(i)))
.collect(Collectors.toList());
// Wait for all to complete
List<String> results = futures.stream()
.map(future -> {
try {
return future.get(30, TimeUnit.SECONDS);
} catch (Exception ex) {
return "Error: " + ex.getMessage();
}
})
.collect(Collectors.toList());Common Patterns and Best Practices
// Pattern 1: Fire-and-forget tasks
public class NotificationService {
private final TaskExecutor taskExecutor;
public NotificationService(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void sendNotification(String message, String recipient) {
taskExecutor.execute(() -> {
// Send email/SMS notification asynchronously
emailService.send(recipient, message);
});
}
}
// Pattern 2: Producer-consumer with task decoration
public class AuditedTaskExecutor implements TaskExecutor {
private final TaskExecutor delegate;
private final AuditService auditService;
public AuditedTaskExecutor(TaskExecutor delegate, AuditService auditService) {
this.delegate = delegate;
this.auditService = auditService;
}
@Override
public void execute(Runnable task) {
String taskId = UUID.randomUUID().toString();
Runnable auditedTask = () -> {
auditService.logTaskStart(taskId);
long startTime = System.currentTimeMillis();
try {
task.run();
auditService.logTaskSuccess(taskId, System.currentTimeMillis() - startTime);
} catch (Exception ex) {
auditService.logTaskFailure(taskId, ex);
throw ex;
}
};
delegate.execute(auditedTask);
}
}
// Pattern 3: Graceful shutdown
public class GracefulTaskExecutor implements AsyncTaskExecutor, DisposableBean {
private final AsyncTaskExecutor delegate;
private final List<Future<?>> activeTasks = Collections.synchronizedList(new ArrayList<>());
private volatile boolean shutdownRequested = false;
public GracefulTaskExecutor(AsyncTaskExecutor delegate) {
this.delegate = delegate;
}
@Override
public Future<?> submit(Runnable task) {
if (shutdownRequested) {
throw new IllegalStateException("Executor is shutting down");
}
Future<?> future = delegate.submit(() -> {
try {
task.run();
} finally {
activeTasks.removeIf(f -> f.isDone() || f.isCancelled());
}
});
activeTasks.add(future);
return future;
}
@Override
public void destroy() throws Exception {
shutdownRequested = true;
// Wait for active tasks to complete
long deadline = System.currentTimeMillis() + 30000; // 30 second timeout
while (!activeTasks.isEmpty() && System.currentTimeMillis() < deadline) {
Thread.sleep(100);
activeTasks.removeIf(f -> f.isDone() || f.isCancelled());
}
// Cancel remaining tasks
activeTasks.forEach(future -> future.cancel(true));
}
}This task execution framework provides the foundation for Spring's asynchronous processing capabilities, enabling developers to build scalable, non-blocking applications with proper resource management and lifecycle control.
Install with Tessl CLI
npx tessl i tessl/maven-org-springframework--spring-core