Skip to content

Commit 65d163e

Browse files
committed
Revised scheduling lifecycle integration
ScheduledAnnotationBeanPostProcessor uses getBean(Class) for TaskScheduler/ScheduledExecutorService retrieval, allowing for a scheduler bean to be flagged as primary, and for a TaskScheduler bean to override a ScheduledExecutorService bean. ContextLifecycleScheduledTaskRegistrar hooks into SmartInitializingSingleton's afterSingletonsInstantiated callback instead of ContextRefreshedEvent, as a natural consequence of SmartInitializingSingleton's introduction in Spring Framework 4.1 GA.
1 parent 7d22315 commit 65d163e

File tree

2 files changed

+36
-52
lines changed

2 files changed

+36
-52
lines changed

spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.lang.reflect.Method;
2020
import java.lang.reflect.Modifier;
2121
import java.util.Collections;
22-
import java.util.HashMap;
2322
import java.util.LinkedHashSet;
2423
import java.util.Map;
2524
import java.util.Set;
@@ -35,6 +34,8 @@
3534
import org.springframework.beans.factory.BeanFactoryAware;
3635
import org.springframework.beans.factory.DisposableBean;
3736
import org.springframework.beans.factory.ListableBeanFactory;
37+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
38+
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
3839
import org.springframework.beans.factory.SmartInitializingSingleton;
3940
import org.springframework.beans.factory.config.BeanPostProcessor;
4041
import org.springframework.context.ApplicationContext;
@@ -87,7 +88,7 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
8788

8889
private StringValueResolver embeddedValueResolver;
8990

90-
private ListableBeanFactory beanFactory;
91+
private BeanFactory beanFactory;
9192

9293
private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();
9394

@@ -121,7 +122,7 @@ public void setEmbeddedValueResolver(StringValueResolver resolver) {
121122
*/
122123
@Override
123124
public void setBeanFactory(BeanFactory beanFactory) {
124-
this.beanFactory = (beanFactory instanceof ListableBeanFactory ? (ListableBeanFactory) beanFactory : null);
125+
this.beanFactory = beanFactory;
125126
}
126127

127128
/**
@@ -141,30 +142,40 @@ public void afterSingletonsInstantiated() {
141142
this.registrar.setScheduler(this.scheduler);
142143
}
143144

144-
if (this.beanFactory != null) {
145-
Map<String, SchedulingConfigurer> configurers = this.beanFactory.getBeansOfType(SchedulingConfigurer.class);
145+
if (this.beanFactory instanceof ListableBeanFactory) {
146+
Map<String, SchedulingConfigurer> configurers =
147+
((ListableBeanFactory) this.beanFactory).getBeansOfType(SchedulingConfigurer.class);
146148
for (SchedulingConfigurer configurer : configurers.values()) {
147149
configurer.configureTasks(this.registrar);
148150
}
149151
}
150152

151153
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
152154
Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
153-
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
154-
schedulers.putAll(this.beanFactory.getBeansOfType(TaskScheduler.class));
155-
schedulers.putAll(this.beanFactory.getBeansOfType(ScheduledExecutorService.class));
156-
if (schedulers.size() == 0) {
157-
// do nothing -> fall back to default scheduler
155+
try {
156+
// Search for TaskScheduler bean...
157+
this.registrar.setScheduler(this.beanFactory.getBean(TaskScheduler.class));
158158
}
159-
else if (schedulers.size() == 1) {
160-
this.registrar.setScheduler(schedulers.values().iterator().next());
159+
catch (NoUniqueBeanDefinitionException ex) {
160+
throw new IllegalStateException("More than one TaskScheduler exists within the context. " +
161+
"Remove all but one of the beans; or implement the SchedulingConfigurer interface and call " +
162+
"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback.", ex);
161163
}
162-
else if (schedulers.size() >= 2){
163-
throw new IllegalStateException("More than one TaskScheduler and/or ScheduledExecutorService " +
164-
"exist within the context. Remove all but one of the beans; or implement the " +
165-
"SchedulingConfigurer interface and call ScheduledTaskRegistrar#setScheduler " +
166-
"explicitly within the configureTasks() callback. Found the following beans: " +
167-
schedulers.keySet());
164+
catch (NoSuchBeanDefinitionException ex) {
165+
logger.debug("Could not find default TaskScheduler bean", ex);
166+
// Search for ScheduledExecutorService bean next...
167+
try {
168+
this.registrar.setScheduler(this.beanFactory.getBean(ScheduledExecutorService.class));
169+
}
170+
catch (NoUniqueBeanDefinitionException ex2) {
171+
throw new IllegalStateException("More than one ScheduledExecutorService exists within the context. " +
172+
"Remove all but one of the beans; or implement the SchedulingConfigurer interface and call " +
173+
"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback.", ex);
174+
}
175+
catch (NoSuchBeanDefinitionException ex2) {
176+
logger.debug("Could not find default ScheduledExecutorService bean", ex);
177+
// Giving up -> falling back to default scheduler within the registrar...
178+
}
168179
}
169180
}
170181

spring-context/src/main/java/org/springframework/scheduling/config/ContextLifecycleScheduledTaskRegistrar.java

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,51 +16,24 @@
1616

1717
package org.springframework.scheduling.config;
1818

19-
import org.springframework.context.ApplicationContext;
20-
import org.springframework.context.ApplicationContextAware;
21-
import org.springframework.context.ApplicationListener;
22-
import org.springframework.context.event.ContextRefreshedEvent;
19+
import org.springframework.beans.factory.SmartInitializingSingleton;
2320

2421
/**
25-
* {@link ScheduledTaskRegistrar} subclass that redirects the actual scheduling
26-
* of tasks to the {@link ContextRefreshedEvent} callback. Falls back to regular
27-
* {@code ScheduledTaskRegistrar} behavior when not running within an ApplicationContext.
22+
* {@link ScheduledTaskRegistrar} subclass which redirects the actual scheduling
23+
* of tasks to the {@link #afterSingletonsInstantiated()} callback (as of 4.1.2).
2824
*
2925
* @author Juergen Hoeller
3026
* @since 3.2.1
3127
*/
32-
public class ContextLifecycleScheduledTaskRegistrar extends ScheduledTaskRegistrar
33-
implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
28+
public class ContextLifecycleScheduledTaskRegistrar extends ScheduledTaskRegistrar implements SmartInitializingSingleton {
3429

35-
private ApplicationContext applicationContext;
36-
37-
38-
@Override
39-
public void setApplicationContext(ApplicationContext applicationContext) {
40-
this.applicationContext = applicationContext;
41-
}
42-
43-
44-
/**
45-
* If we're running within an ApplicationContext, don't schedule the tasks
46-
* right here; wait for this context's ContextRefreshedEvent instead.
47-
*/
4830
@Override
4931
public void afterPropertiesSet() {
50-
if (this.applicationContext == null) {
51-
scheduleTasks();
52-
}
32+
// no-op
5333
}
5434

55-
/**
56-
* Actually schedule the tasks at the right time of the context lifecycle,
57-
* if we're running within an ApplicationContext.
58-
*/
5935
@Override
60-
public void onApplicationEvent(ContextRefreshedEvent event) {
61-
if (event.getApplicationContext() != this.applicationContext) {
62-
return;
63-
}
36+
public void afterSingletonsInstantiated() {
6437
scheduleTasks();
6538
}
6639

0 commit comments

Comments
 (0)