0
# Scheduling
1
2
Task scheduling and asynchronous execution capabilities providing comprehensive support for background processing, periodic tasks, and asynchronous method execution. This includes @Scheduled and @Async annotations, TaskScheduler interfaces, and execution configuration options.
3
4
## Capabilities
5
6
### Scheduled Task Annotations
7
8
Declarative task scheduling through annotations that automatically register methods for periodic execution.
9
10
```java { .api }
11
/**
12
* An annotation that marks a method to be scheduled. Exactly one of the cron(), fixedDelay(), or fixedRate()
13
* attributes must be specified.
14
*/
15
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
16
@Retention(RetentionPolicy.RUNTIME)
17
@Repeatable(Schedules.class)
18
public @interface Scheduled {
19
/**
20
* A cron-like expression, extending the usual UN*X definition to include triggers on the second as well as minute, hour, day of month, month and day of week.
21
* @return an expression that can be parsed to a cron schedule
22
*/
23
String cron() default "";
24
25
/**
26
* A time zone for which the cron expression will be resolved.
27
* @return a zone id (ZoneId.of(String)), or an empty String to indicate the server's local time zone
28
*/
29
String zone() default "";
30
31
/**
32
* Execute the annotated method with a fixed period between the end of the last invocation and the start of the next.
33
* @return the delay in milliseconds
34
*/
35
long fixedDelay() default -1;
36
37
/**
38
* Execute the annotated method with a fixed period between the end of the last invocation and the start of the next.
39
* @return the delay as a String value, e.g. a placeholder or a java.time.Duration compliant value
40
*/
41
String fixedDelayString() default "";
42
43
/**
44
* Execute the annotated method with a fixed period between invocations.
45
* @return the period in milliseconds
46
*/
47
long fixedRate() default -1;
48
49
/**
50
* Execute the annotated method with a fixed period between invocations.
51
* @return the period as a String value, e.g. a placeholder or a java.time.Duration compliant value
52
*/
53
String fixedRateString() default "";
54
55
/**
56
* Number of milliseconds to delay before the first execution of a fixedRate() or fixedDelay() task.
57
* @return the initial delay in milliseconds
58
*/
59
long initialDelay() default -1;
60
61
/**
62
* Number of milliseconds to delay before the first execution of a fixedRate() or fixedDelay() task.
63
* @return the initial delay as a String value, e.g. a placeholder or a java.time.Duration compliant value
64
*/
65
String initialDelayString() default "";
66
67
/**
68
* The TimeUnit to use for fixedDelay(), fixedRate(), and initialDelay() values.
69
* @return the TimeUnit to use
70
*/
71
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
72
73
/**
74
* A qualifier value for the specified scheduler.
75
* @return the qualifier value for the scheduler
76
*/
77
String scheduler() default "";
78
}
79
80
/**
81
* Container annotation that aggregates several @Scheduled annotations.
82
*/
83
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
84
@Retention(RetentionPolicy.RUNTIME)
85
public @interface Schedules {
86
Scheduled[] value();
87
}
88
89
/**
90
* Enables Spring's scheduled task execution capability, similar to functionality found in Spring's task namespace.
91
*/
92
@Target(ElementType.TYPE)
93
@Retention(RetentionPolicy.RUNTIME)
94
@Import(SchedulingConfiguration.class)
95
public @interface EnableScheduling {
96
}
97
```
98
99
### Asynchronous Execution Annotations
100
101
Annotations for declarative asynchronous method execution.
102
103
```java { .api }
104
/**
105
* Annotation that marks a method as a candidate for asynchronous execution.
106
* Can also be used at the type level, in which case all of the type's methods are considered as asynchronous.
107
*/
108
@Target({ElementType.TYPE, ElementType.METHOD})
109
@Retention(RetentionPolicy.RUNTIME)
110
public @interface Async {
111
/**
112
* A qualifier value for the specified async operation(s).
113
* @return the qualifier value for the async executor
114
*/
115
String value() default "";
116
}
117
118
/**
119
* Enables Spring's asynchronous method execution capability, similar to functionality found in Spring's task namespace.
120
*/
121
@Target(ElementType.TYPE)
122
@Retention(RetentionPolicy.RUNTIME)
123
@Import(AsyncConfigurationSelector.class)
124
public @interface EnableAsync {
125
/**
126
* Indicate the 'async' annotation type to be detected at either class or method level.
127
* @return the desired annotation type for async processing
128
*/
129
Class<? extends Annotation> annotation() default Async.class;
130
131
/**
132
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies.
133
* @return whether to proxy the target class
134
*/
135
boolean proxyTargetClass() default false;
136
137
/**
138
* Indicate how async advice should be applied.
139
* @return the advice mode
140
*/
141
AdviceMode mode() default AdviceMode.PROXY;
142
143
/**
144
* Indicate the order in which the AsyncAnnotationBeanPostProcessor should be applied.
145
* @return the order for the async post processor
146
*/
147
int order() default Ordered.LOWEST_PRECEDENCE;
148
}
149
```
150
151
### Task Scheduler Interfaces
152
153
Core interfaces for task scheduling functionality.
154
155
```java { .api }
156
/**
157
* Task scheduler interface that abstracts the scheduling of Runnable tasks based on different kinds of triggers.
158
*/
159
public interface TaskScheduler {
160
/**
161
* Return the clock to use for scheduling purposes.
162
* @return the clock instance (never null)
163
*/
164
default Clock getClock() {
165
return Clock.systemDefaultZone();
166
}
167
168
/**
169
* Schedule the given Runnable, invoking it whenever the trigger indicates a next execution time.
170
* @param task the Runnable to execute whenever the trigger fires
171
* @param trigger an implementation of the Trigger interface, e.g. a CronTrigger object wrapping a cron expression
172
* @return a ScheduledFuture representing pending completion of the task, or null if the given Trigger object never fires
173
*/
174
ScheduledFuture<?> schedule(Runnable task, Trigger trigger);
175
176
/**
177
* Schedule the given Runnable for execution at the given time.
178
* @param task the Runnable to execute
179
* @param startTime the desired execution time for the task
180
* @return a ScheduledFuture representing pending completion of the task
181
*/
182
ScheduledFuture<?> schedule(Runnable task, Instant startTime);
183
184
/**
185
* Schedule the given Runnable for repeated execution, starting at the given time and subsequently with the given period.
186
* @param task the Runnable to execute
187
* @param startTime the desired first execution time for the task
188
* @param period the interval between successive executions of the task
189
* @return a ScheduledFuture representing pending completion of the task
190
*/
191
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Instant startTime, Duration period);
192
193
/**
194
* Schedule the given Runnable for repeated execution, starting as soon as possible and subsequently with the given period.
195
* @param task the Runnable to execute
196
* @param period the interval between successive executions of the task
197
* @return a ScheduledFuture representing pending completion of the task
198
*/
199
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period);
200
201
/**
202
* Schedule the given Runnable for repeated execution, starting at the given time and subsequently with the given delay between the completion of one execution and the start of the next.
203
* @param task the Runnable to execute
204
* @param startTime the desired first execution time for the task
205
* @param delay the delay between the completion of one execution and the start of the next
206
* @return a ScheduledFuture representing pending completion of the task
207
*/
208
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay);
209
210
/**
211
* Schedule the given Runnable for repeated execution, starting as soon as possible and subsequently with the given delay between the completion of one execution and the start of the next.
212
* @param task the Runnable to execute
213
* @param delay the delay between the completion of one execution and the start of the next
214
* @return a ScheduledFuture representing pending completion of the task
215
*/
216
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay);
217
}
218
219
/**
220
* A TaskExecutor extension exposing scheduling characteristics that are relevant to potential task submitters.
221
*/
222
public interface SchedulingTaskExecutor extends TaskExecutor {
223
/**
224
* Does this TaskExecutor prefer short-lived tasks over long-lived tasks?
225
* @return true if this executor prefers short-lived tasks
226
*/
227
default boolean prefersShortLivedTasks() {
228
return true;
229
}
230
}
231
```
232
233
### Trigger Interfaces
234
235
Interfaces for defining when scheduled tasks should execute.
236
237
```java { .api }
238
/**
239
* Common interface for trigger objects that determine the next execution time of a task that they get associated with.
240
*/
241
public interface Trigger {
242
/**
243
* Determine the next execution time according to the given trigger context.
244
* @param triggerContext context object encapsulating last execution times and last completion time
245
* @return the next execution time as defined by the trigger, or null if the trigger won't fire anymore
246
*/
247
Instant nextExecution(TriggerContext triggerContext);
248
}
249
250
/**
251
* Context object encapsulating last execution times and last completion time of a given task.
252
*/
253
public interface TriggerContext {
254
/**
255
* Return the clock to use for trigger calculation purposes.
256
* @return the clock instance (never null)
257
*/
258
default Clock getClock() {
259
return Clock.systemDefaultZone();
260
}
261
262
/**
263
* Return the last scheduled execution time of the task, or null if not scheduled before.
264
* @return the last scheduled execution time, or null if none
265
*/
266
Instant lastScheduledExecution();
267
268
/**
269
* Return the last actual execution time of the task, or null if not scheduled before.
270
* @return the last actual execution time, or null if none
271
*/
272
Instant lastActualExecution();
273
274
/**
275
* Return the last completion time of the task, or null if not scheduled before.
276
* @return the last completion time, or null if none
277
*/
278
Instant lastCompletion();
279
}
280
281
/**
282
* Trigger implementation for cron expressions.
283
*/
284
public class CronTrigger implements Trigger {
285
/**
286
* Build a CronTrigger from the pattern provided in the default time zone.
287
* @param expression a space-separated list of time fields
288
*/
289
public CronTrigger(String expression) {}
290
291
/**
292
* Build a CronTrigger from the pattern provided in the given time zone.
293
* @param expression a space-separated list of time fields
294
* @param timeZone the time zone in which the trigger times will be generated
295
*/
296
public CronTrigger(String expression, ZoneId timeZone) {}
297
298
/**
299
* Return the cron pattern that this trigger was built with.
300
* @return the cron expression
301
*/
302
public String getExpression() {}
303
304
/**
305
* Determine the next execution time according to the given trigger context.
306
* @param triggerContext context object encapsulating last execution times and last completion time
307
* @return the next execution time as defined by the trigger, or null if the trigger won't fire anymore
308
*/
309
public Instant nextExecution(TriggerContext triggerContext) {}
310
}
311
312
/**
313
* Trigger implementation for periodic task execution.
314
*/
315
public class PeriodicTrigger implements Trigger {
316
/**
317
* Create a trigger with the given period in the default time unit (milliseconds).
318
* @param period the interval between executions
319
* @param timeUnit the time unit for the period
320
*/
321
public PeriodicTrigger(Duration period) {}
322
323
/**
324
* Specify the delay between the completion of one execution and the start of the next.
325
* @param fixedRate whether to use fixed rate (true) or fixed delay (false)
326
*/
327
public void setFixedRate(boolean fixedRate) {}
328
329
/**
330
* Specify the delay before the first execution of the task.
331
* @param initialDelay the initial delay
332
*/
333
public void setInitialDelay(Duration initialDelay) {}
334
335
/**
336
* Return the interval between successive executions.
337
* @return the period for this trigger
338
*/
339
public Duration getPeriod() {}
340
341
/**
342
* Return whether this trigger uses fixed rate execution.
343
* @return true if fixed rate, false if fixed delay
344
*/
345
public boolean isFixedRate() {}
346
347
/**
348
* Return the initial delay before first execution.
349
* @return the initial delay
350
*/
351
public Duration getInitialDelay() {}
352
353
/**
354
* Determine the next execution time according to the given trigger context.
355
* @param triggerContext context object encapsulating last execution times and last completion time
356
* @return the next execution time as defined by the trigger, or null if the trigger won't fire anymore
357
*/
358
public Instant nextExecution(TriggerContext triggerContext) {}
359
}
360
```
361
362
### Async Configuration Support
363
364
Interfaces and classes for configuring asynchronous execution behavior.
365
366
```java { .api }
367
/**
368
* Interface to be implemented by @Configuration classes annotated with @EnableAsync
369
* that wish to customize the Executor instance used when processing async method invocations.
370
*/
371
public interface AsyncConfigurer {
372
/**
373
* The Executor instance to be used when processing async method invocations.
374
* @return the async executor instance
375
*/
376
default Executor getAsyncExecutor() {
377
return null;
378
}
379
380
/**
381
* The AsyncUncaughtExceptionHandler instance to be used when an exception is thrown during an asynchronous method execution with void return type.
382
* @return the async exception handler instance
383
*/
384
default AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
385
return null;
386
}
387
}
388
389
/**
390
* Empty implementation of AsyncConfigurer for convenient subclassing.
391
*/
392
public class AsyncConfigurerSupport implements AsyncConfigurer {
393
/**
394
* The default implementation returns null so that the framework will use a SimpleAsyncTaskExecutor in combination with a SimpleAsyncTaskScheduler.
395
* @return null
396
*/
397
@Override
398
public Executor getAsyncExecutor() {
399
return null;
400
}
401
402
/**
403
* The default implementation returns null so that the framework will log the exception at ERROR level.
404
* @return null
405
*/
406
@Override
407
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
408
return null;
409
}
410
}
411
412
/**
413
* Interface to be implemented by @Configuration classes annotated with @EnableScheduling
414
* that wish to register Trigger tasks in a declarative manner.
415
*/
416
public interface SchedulingConfigurer {
417
/**
418
* Callback allowing a TaskScheduler and specific Task instances to be registered against the given the ScheduledTaskRegistrar.
419
* @param taskRegistrar the registrar to be configured
420
*/
421
default void configureTasks(ScheduledTaskRegistrar taskRegistrar) {}
422
}
423
```
424
425
### Async Result Support
426
427
Classes for handling return values from asynchronous methods.
428
429
```java { .api }
430
/**
431
* A pass-through Future handle that can be used for method signatures which are declared with a Future return type for asynchronous execution.
432
*/
433
public class AsyncResult<V> implements ListenableFuture<V> {
434
/** The result value */
435
private final V value;
436
437
/** The exception */
438
private final Throwable executionException;
439
440
/**
441
* Create a new AsyncResult holder.
442
* @param value the value to pass through
443
*/
444
public AsyncResult(V value) {}
445
446
/**
447
* Create a new AsyncResult holder.
448
* @param ex the exception to pass through
449
*/
450
public AsyncResult(Throwable ex) {}
451
452
/**
453
* Cancel the execution of the task.
454
* @param mayInterruptIfRunning whether the thread executing the task should be interrupted
455
* @return false
456
*/
457
public boolean cancel(boolean mayInterruptIfRunning) {}
458
459
/**
460
* Return whether the task was cancelled.
461
* @return false
462
*/
463
public boolean isCancelled() {}
464
465
/**
466
* Return whether the task has completed.
467
* @return true
468
*/
469
public boolean isDone() {}
470
471
/**
472
* Retrieve the result value.
473
* @return the result value (never null)
474
* @throws ExecutionException if the async method threw an exception
475
* @throws InterruptedException if the current thread was interrupted while waiting
476
*/
477
public V get() throws ExecutionException {}
478
479
/**
480
* Retrieve the result value.
481
* @param timeout the maximum time to wait
482
* @param unit the time unit of the timeout argument
483
* @return the result value (never null)
484
* @throws ExecutionException if the async method threw an exception
485
* @throws InterruptedException if the current thread was interrupted while waiting
486
* @throws TimeoutException if the wait timed out
487
*/
488
public V get(long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {}
489
490
/**
491
* Add a completion callback to this ListenableFuture.
492
* @param callback the callback to add
493
*/
494
public void addCallback(ListenableFutureCallback<? super V> callback) {}
495
496
/**
497
* Add separate success and failure callbacks to this ListenableFuture.
498
* @param successCallback the success callback
499
* @param failureCallback the failure callback
500
*/
501
public void addCallback(SuccessCallback<? super V> successCallback, FailureCallback failureCallback) {}
502
503
/**
504
* Return a CompletableFuture that completes when this ListenableFuture completes.
505
* @return the CompletableFuture adaptation
506
*/
507
public CompletableFuture<V> completable() {}
508
}
509
```
510
511
### Exception Handling
512
513
Interfaces and classes for handling exceptions in scheduled and asynchronous execution.
514
515
```java { .api }
516
/**
517
* A strategy for handling uncaught exceptions thrown from asynchronous methods.
518
*/
519
@FunctionalInterface
520
public interface AsyncUncaughtExceptionHandler {
521
/**
522
* Handle the given uncaught exception thrown from an asynchronous method.
523
* @param ex the exception thrown from the asynchronous method
524
* @param method the asynchronous method
525
* @param params the parameters used to invoke the method
526
*/
527
void handleUncaughtException(Throwable ex, Method method, Object... params);
528
}
529
530
/**
531
* A default AsyncUncaughtExceptionHandler that simply logs the exception.
532
*/
533
public class SimpleAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
534
/**
535
* Handle the given uncaught exception thrown from an asynchronous method.
536
* @param ex the exception thrown from the asynchronous method
537
* @param method the asynchronous method
538
* @param params the parameters used to invoke the method
539
*/
540
public void handleUncaughtException(Throwable ex, Method method, Object... params) {}
541
}
542
543
/**
544
* Exception to be thrown when an asynchronous execution attempt fails.
545
*/
546
public class SchedulingException extends RuntimeException {
547
/**
548
* Constructor for SchedulingException.
549
* @param msg the detail message
550
*/
551
public SchedulingException(String msg) {}
552
553
/**
554
* Constructor for SchedulingException.
555
* @param msg the detail message
556
* @param cause the root cause (usually from using a underlying scheduling API such as Quartz)
557
*/
558
public SchedulingException(String msg, Throwable cause) {}
559
}
560
```
561
562
### Usage Examples
563
564
**Basic Scheduled Methods:**
565
566
```java
567
import org.springframework.scheduling.annotation.Scheduled;
568
import org.springframework.scheduling.annotation.EnableScheduling;
569
import org.springframework.stereotype.Component;
570
571
@Configuration
572
@EnableScheduling
573
public class SchedulingConfig {
574
}
575
576
@Component
577
public class ScheduledTasks {
578
579
// Fixed rate execution - runs every 5 seconds
580
@Scheduled(fixedRate = 5000)
581
public void reportCurrentTime() {
582
System.out.println("Current time: " + new Date());
583
}
584
585
// Fixed delay execution - waits 3 seconds after completion before next execution
586
@Scheduled(fixedDelay = 3000)
587
public void processData() {
588
System.out.println("Processing data...");
589
// Simulate processing time
590
try {
591
Thread.sleep(2000);
592
} catch (InterruptedException e) {
593
Thread.currentThread().interrupt();
594
}
595
}
596
597
// Cron expression - runs every day at 2:00 AM
598
@Scheduled(cron = "0 0 2 * * ?")
599
public void performDailyMaintenance() {
600
System.out.println("Performing daily maintenance...");
601
}
602
603
// Initial delay with fixed rate
604
@Scheduled(initialDelay = 10000, fixedRate = 30000)
605
public void delayedTask() {
606
System.out.println("Task with initial delay");
607
}
608
609
// Using string expressions with property placeholders
610
@Scheduled(fixedDelayString = "${app.task.delay:5000}")
611
public void configurableTask() {
612
System.out.println("Configurable scheduled task");
613
}
614
615
// Using time units other than milliseconds
616
@Scheduled(fixedRate = 30, timeUnit = TimeUnit.SECONDS)
617
public void thirtySecondTask() {
618
System.out.println("Task runs every 30 seconds");
619
}
620
}
621
```
622
623
**Advanced Cron Expressions:**
624
625
```java
626
@Component
627
public class CronScheduledTasks {
628
629
// Every 15 minutes
630
@Scheduled(cron = "0 */15 * * * ?")
631
public void everyFifteenMinutes() {
632
System.out.println("Running every 15 minutes");
633
}
634
635
// Monday to Friday at 9:00 AM
636
@Scheduled(cron = "0 0 9 * * MON-FRI")
637
public void weekdayMorningTask() {
638
System.out.println("Weekday morning task");
639
}
640
641
// Last day of every month at midnight
642
@Scheduled(cron = "0 0 0 L * ?")
643
public void lastDayOfMonth() {
644
System.out.println("Last day of month task");
645
}
646
647
// Every 30 seconds on weekdays during business hours
648
@Scheduled(cron = "*/30 * 9-17 * * MON-FRI")
649
public void businessHoursTask() {
650
System.out.println("Business hours task");
651
}
652
653
// With timezone specification
654
@Scheduled(cron = "0 0 12 * * ?", zone = "America/New_York")
655
public void noonInNewYork() {
656
System.out.println("Noon in New York");
657
}
658
}
659
```
660
661
**Asynchronous Methods:**
662
663
```java
664
import org.springframework.scheduling.annotation.Async;
665
import org.springframework.scheduling.annotation.EnableAsync;
666
import java.util.concurrent.CompletableFuture;
667
import java.util.concurrent.Future;
668
669
@Configuration
670
@EnableAsync
671
public class AsyncConfig {
672
673
@Bean
674
public Executor taskExecutor() {
675
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
676
executor.setCorePoolSize(2);
677
executor.setMaxPoolSize(10);
678
executor.setQueueCapacity(100);
679
executor.setThreadNamePrefix("async-");
680
executor.initialize();
681
return executor;
682
}
683
}
684
685
@Service
686
public class AsyncService {
687
688
// Simple async method with void return
689
@Async
690
public void performAsyncTask() {
691
System.out.println("Async task started: " + Thread.currentThread().getName());
692
try {
693
Thread.sleep(2000);
694
} catch (InterruptedException e) {
695
Thread.currentThread().interrupt();
696
}
697
System.out.println("Async task completed");
698
}
699
700
// Async method returning Future
701
@Async
702
public Future<String> asyncMethodWithReturn() {
703
System.out.println("Async method with return: " + Thread.currentThread().getName());
704
try {
705
Thread.sleep(3000);
706
} catch (InterruptedException e) {
707
Thread.currentThread().interrupt();
708
return new AsyncResult<>("Interrupted");
709
}
710
return new AsyncResult<>("Task completed successfully");
711
}
712
713
// Async method returning CompletableFuture
714
@Async
715
public CompletableFuture<String> asyncWithCompletableFuture() {
716
return CompletableFuture.supplyAsync(() -> {
717
try {
718
Thread.sleep(1000);
719
return "CompletableFuture result";
720
} catch (InterruptedException e) {
721
Thread.currentThread().interrupt();
722
throw new RuntimeException(e);
723
}
724
});
725
}
726
727
// Async method with specific executor
728
@Async("taskExecutor")
729
public void asyncWithSpecificExecutor() {
730
System.out.println("Using specific executor: " + Thread.currentThread().getName());
731
}
732
}
733
```
734
735
**Custom Async Configuration:**
736
737
```java
738
@Configuration
739
@EnableAsync
740
public class CustomAsyncConfig implements AsyncConfigurer {
741
742
@Override
743
public Executor getAsyncExecutor() {
744
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
745
executor.setCorePoolSize(4);
746
executor.setMaxPoolSize(20);
747
executor.setQueueCapacity(200);
748
executor.setThreadNamePrefix("custom-async-");
749
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
750
executor.initialize();
751
return executor;
752
}
753
754
@Override
755
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
756
return new CustomAsyncExceptionHandler();
757
}
758
759
// Additional executor for specific tasks
760
@Bean("emailExecutor")
761
public Executor emailExecutor() {
762
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
763
executor.setCorePoolSize(2);
764
executor.setMaxPoolSize(5);
765
executor.setQueueCapacity(50);
766
executor.setThreadNamePrefix("email-");
767
executor.initialize();
768
return executor;
769
}
770
}
771
772
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
773
774
@Override
775
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
776
System.err.println("Uncaught async exception in method: " + method.getName());
777
System.err.println("Parameters: " + Arrays.toString(params));
778
System.err.println("Exception: " + ex.getMessage());
779
780
// Log to monitoring system, send alerts, etc.
781
logToMonitoringSystem(ex, method, params);
782
}
783
784
private void logToMonitoringSystem(Throwable ex, Method method, Object... params) {
785
// Implementation for logging to external monitoring system
786
}
787
}
788
```
789
790
**Programmatic Task Scheduling:**
791
792
```java
793
@Service
794
public class DynamicSchedulingService {
795
796
@Autowired
797
private TaskScheduler taskScheduler;
798
799
private final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
800
801
// Schedule a task dynamically
802
public void scheduleTask(String taskId, Runnable task, String cronExpression) {
803
ScheduledFuture<?> future = taskScheduler.schedule(task, new CronTrigger(cronExpression));
804
scheduledTasks.put(taskId, future);
805
}
806
807
// Schedule with fixed delay
808
public void scheduleWithFixedDelay(String taskId, Runnable task, Duration delay) {
809
ScheduledFuture<?> future = taskScheduler.scheduleWithFixedDelay(task, delay);
810
scheduledTasks.put(taskId, future);
811
}
812
813
// Cancel a scheduled task
814
public boolean cancelTask(String taskId) {
815
ScheduledFuture<?> future = scheduledTasks.remove(taskId);
816
if (future != null) {
817
return future.cancel(false);
818
}
819
return false;
820
}
821
822
// Example dynamic task creation
823
public void createUserMaintenanceTask(String userId, String schedule) {
824
Runnable maintenanceTask = () -> {
825
System.out.println("Performing maintenance for user: " + userId);
826
// Perform user-specific maintenance
827
};
828
829
scheduleTask("user-maintenance-" + userId, maintenanceTask, schedule);
830
}
831
}
832
```
833
834
**Scheduled and Async Together:**
835
836
```java
837
@Service
838
public class ScheduledAsyncService {
839
840
@Autowired
841
private EmailService emailService;
842
843
@Autowired
844
private ReportService reportService;
845
846
// Scheduled method that triggers async operations
847
@Scheduled(cron = "0 0 8 * * MON-FRI") // Every weekday at 8 AM
848
public void sendDailyReports() {
849
System.out.println("Starting daily report generation...");
850
851
// Get list of users
852
List<User> users = userService.getAllActiveUsers();
853
854
// Send reports asynchronously for each user
855
for (User user : users) {
856
sendReportAsync(user);
857
}
858
}
859
860
@Async
861
public void sendReportAsync(User user) {
862
try {
863
// Generate report (potentially time-consuming)
864
Report report = reportService.generateUserReport(user);
865
866
// Send email
867
emailService.sendReport(user.getEmail(), report);
868
869
System.out.println("Report sent to: " + user.getEmail());
870
} catch (Exception e) {
871
System.err.println("Failed to send report to: " + user.getEmail());
872
// Log error or handle appropriately
873
}
874
}
875
876
// Another scheduled task with async processing
877
@Scheduled(fixedRate = 300000) // Every 5 minutes
878
public void processBackgroundTasks() {
879
List<BackgroundTask> tasks = taskRepository.findPendingTasks();
880
881
tasks.forEach(this::processTaskAsync);
882
}
883
884
@Async
885
public CompletableFuture<Void> processTaskAsync(BackgroundTask task) {
886
return CompletableFuture.runAsync(() -> {
887
try {
888
// Process the task
889
taskProcessor.process(task);
890
task.markCompleted();
891
taskRepository.save(task);
892
} catch (Exception e) {
893
task.markFailed();
894
taskRepository.save(task);
895
}
896
});
897
}
898
}
899
```