17
17
package org .springframework .scheduling .annotation ;
18
18
19
19
import java .lang .reflect .Method ;
20
+ import java .util .Collection ;
20
21
import java .util .Collections ;
22
+ import java .util .LinkedHashSet ;
21
23
import java .util .Map ;
22
24
import java .util .Set ;
23
25
import java .util .TimeZone ;
35
37
import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
36
38
import org .springframework .beans .factory .NoUniqueBeanDefinitionException ;
37
39
import org .springframework .beans .factory .SmartInitializingSingleton ;
38
- import org .springframework .beans .factory .config .BeanPostProcessor ;
40
+ import org .springframework .beans .factory .config .DestructionAwareBeanPostProcessor ;
39
41
import org .springframework .context .ApplicationContext ;
40
42
import org .springframework .context .ApplicationContextAware ;
41
43
import org .springframework .context .ApplicationListener ;
48
50
import org .springframework .scheduling .Trigger ;
49
51
import org .springframework .scheduling .config .CronTask ;
50
52
import org .springframework .scheduling .config .IntervalTask ;
53
+ import org .springframework .scheduling .config .ScheduledTask ;
51
54
import org .springframework .scheduling .config .ScheduledTaskRegistrar ;
52
55
import org .springframework .scheduling .support .CronTrigger ;
53
56
import org .springframework .scheduling .support .ScheduledMethodRunnable ;
81
84
* @see org.springframework.scheduling.config.ScheduledTaskRegistrar
82
85
* @see AsyncAnnotationBeanPostProcessor
83
86
*/
84
- public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor , Ordered ,
85
- EmbeddedValueResolverAware , BeanFactoryAware , ApplicationContextAware ,
87
+ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor ,
88
+ Ordered , EmbeddedValueResolverAware , BeanFactoryAware , ApplicationContextAware ,
86
89
SmartInitializingSingleton , ApplicationListener <ContextRefreshedEvent >, DisposableBean {
87
90
88
91
/**
@@ -109,6 +112,9 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
109
112
private final Set <Class <?>> nonAnnotatedClasses =
110
113
Collections .newSetFromMap (new ConcurrentHashMap <Class <?>, Boolean >(64 ));
111
114
115
+ private final Map <Object , Set <ScheduledTask >> scheduledTasks =
116
+ new ConcurrentHashMap <Object , Set <ScheduledTask >>(16 );
117
+
112
118
113
119
@ Override
114
120
public int getOrder () {
@@ -296,6 +302,9 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
296
302
String errorMessage =
297
303
"Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required" ;
298
304
305
+ Set <ScheduledTask > tasks =
306
+ new LinkedHashSet <ScheduledTask >(4 );
307
+
299
308
// Determine initial delay
300
309
long initialDelay = scheduled .initialDelay ();
301
310
String initialDelayString = scheduled .initialDelayString ();
@@ -330,7 +339,7 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
330
339
else {
331
340
timeZone = TimeZone .getDefault ();
332
341
}
333
- this .registrar .addCronTask (new CronTask (runnable , new CronTrigger (cron , timeZone )));
342
+ tasks . add ( this .registrar .scheduleCronTask (new CronTask (runnable , new CronTrigger (cron , timeZone ) )));
334
343
}
335
344
336
345
// At this point we don't need to differentiate between initial delay set or not anymore
@@ -343,7 +352,7 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
343
352
if (fixedDelay >= 0 ) {
344
353
Assert .isTrue (!processedSchedule , errorMessage );
345
354
processedSchedule = true ;
346
- this .registrar .addFixedDelayTask (new IntervalTask (runnable , fixedDelay , initialDelay ));
355
+ tasks . add ( this .registrar .scheduleFixedDelayTask (new IntervalTask (runnable , fixedDelay , initialDelay ) ));
347
356
}
348
357
String fixedDelayString = scheduled .fixedDelayString ();
349
358
if (StringUtils .hasText (fixedDelayString )) {
@@ -359,15 +368,15 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
359
368
throw new IllegalArgumentException (
360
369
"Invalid fixedDelayString value \" " + fixedDelayString + "\" - cannot parse into integer" );
361
370
}
362
- this .registrar .addFixedDelayTask (new IntervalTask (runnable , fixedDelay , initialDelay ));
371
+ tasks . add ( this .registrar .scheduleFixedDelayTask (new IntervalTask (runnable , fixedDelay , initialDelay ) ));
363
372
}
364
373
365
374
// Check fixed rate
366
375
long fixedRate = scheduled .fixedRate ();
367
376
if (fixedRate >= 0 ) {
368
377
Assert .isTrue (!processedSchedule , errorMessage );
369
378
processedSchedule = true ;
370
- this .registrar .addFixedRateTask (new IntervalTask (runnable , fixedRate , initialDelay ));
379
+ tasks . add ( this .registrar .scheduleFixedRateTask (new IntervalTask (runnable , fixedRate , initialDelay ) ));
371
380
}
372
381
String fixedRateString = scheduled .fixedRateString ();
373
382
if (StringUtils .hasText (fixedRateString )) {
@@ -383,11 +392,12 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
383
392
throw new IllegalArgumentException (
384
393
"Invalid fixedRateString value \" " + fixedRateString + "\" - cannot parse into integer" );
385
394
}
386
- this .registrar .addFixedRateTask (new IntervalTask (runnable , fixedRate , initialDelay ));
395
+ tasks . add ( this .registrar .scheduleFixedRateTask (new IntervalTask (runnable , fixedRate , initialDelay ) ));
387
396
}
388
397
389
398
// Check whether we had any attribute set
390
399
Assert .isTrue (processedSchedule , errorMessage );
400
+ this .scheduledTasks .put (bean , tasks );
391
401
}
392
402
catch (IllegalArgumentException ex ) {
393
403
throw new IllegalStateException (
@@ -396,8 +406,30 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
396
406
}
397
407
398
408
409
+ @ Override
410
+ public void postProcessBeforeDestruction (Object bean , String beanName ) {
411
+ Set <ScheduledTask > tasks = this .scheduledTasks .remove (bean );
412
+ if (tasks != null ) {
413
+ for (ScheduledTask task : tasks ) {
414
+ task .cancel ();
415
+ }
416
+ }
417
+ }
418
+
419
+ @ Override
420
+ public boolean requiresDestruction (Object bean ) {
421
+ return this .scheduledTasks .containsKey (bean );
422
+ }
423
+
399
424
@ Override
400
425
public void destroy () {
426
+ Collection <Set <ScheduledTask >> allTasks = this .scheduledTasks .values ();
427
+ for (Set <ScheduledTask > tasks : allTasks ) {
428
+ for (ScheduledTask task : tasks ) {
429
+ task .cancel ();
430
+ }
431
+ }
432
+ this .scheduledTasks .clear ();
401
433
this .registrar .destroy ();
402
434
}
403
435
0 commit comments