Skip to content

Commit 92c657e

Browse files
committed
JmsListener/ScheduledAnnotationBeanPostProcessor uses SmartInitializingSingleton instead of ContextRefreshedEvent
Also reducing the container dependencies to BeanFactory instead of ApplicationContext, wherever possible. Issue: SPR-12039
1 parent b6389a6 commit 92c657e

File tree

10 files changed

+262
-271
lines changed

10 files changed

+262
-271
lines changed

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

Lines changed: 64 additions & 49 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.
@@ -23,13 +23,14 @@
2323
import java.util.concurrent.ScheduledExecutorService;
2424

2525
import org.springframework.aop.support.AopUtils;
26+
import org.springframework.beans.factory.BeanFactory;
27+
import org.springframework.beans.factory.BeanFactoryAware;
2628
import org.springframework.beans.factory.DisposableBean;
29+
import org.springframework.beans.factory.ListableBeanFactory;
30+
import org.springframework.beans.factory.SmartInitializingSingleton;
2731
import org.springframework.beans.factory.config.BeanPostProcessor;
2832
import org.springframework.context.ApplicationContext;
29-
import org.springframework.context.ApplicationContextAware;
30-
import org.springframework.context.ApplicationListener;
3133
import org.springframework.context.EmbeddedValueResolverAware;
32-
import org.springframework.context.event.ContextRefreshedEvent;
3334
import org.springframework.core.Ordered;
3435
import org.springframework.core.annotation.AnnotationUtils;
3536
import org.springframework.scheduling.TaskScheduler;
@@ -57,7 +58,7 @@
5758
* <p>Auto-detects any {@link SchedulingConfigurer} instances in the container,
5859
* allowing for customization of the scheduler to be used or for fine-grained control
5960
* over task registration (e.g. registration of {@link Trigger} tasks.
60-
* See @{@link EnableScheduling} Javadoc for complete usage details.
61+
* See the @{@link EnableScheduling} javadocs for complete usage details.
6162
*
6263
* @author Mark Fisher
6364
* @author Juergen Hoeller
@@ -70,18 +71,23 @@
7071
* @see org.springframework.scheduling.config.ScheduledTaskRegistrar
7172
*/
7273
public class ScheduledAnnotationBeanPostProcessor
73-
implements BeanPostProcessor, Ordered, EmbeddedValueResolverAware, ApplicationContextAware,
74-
ApplicationListener<ContextRefreshedEvent>, DisposableBean {
74+
implements BeanPostProcessor, Ordered, EmbeddedValueResolverAware, BeanFactoryAware,
75+
SmartInitializingSingleton, DisposableBean {
7576

7677
private Object scheduler;
7778

7879
private StringValueResolver embeddedValueResolver;
7980

80-
private ApplicationContext applicationContext;
81+
private ListableBeanFactory beanFactory;
8182

8283
private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();
8384

8485

86+
@Override
87+
public int getOrder() {
88+
return LOWEST_PRECEDENCE;
89+
}
90+
8591
/**
8692
* Set the {@link org.springframework.scheduling.TaskScheduler} that will invoke
8793
* the scheduled methods, or a {@link java.util.concurrent.ScheduledExecutorService}
@@ -96,16 +102,63 @@ public void setEmbeddedValueResolver(StringValueResolver resolver) {
96102
this.embeddedValueResolver = resolver;
97103
}
98104

105+
/**
106+
* Making a {@link BeanFactory} available is optional; if not set,
107+
* {@link SchedulingConfigurer} beans won't get autodetected and
108+
* a {@link #setScheduler scheduler} has to be explicitly configured.
109+
*/
99110
@Override
111+
public void setBeanFactory(BeanFactory beanFactory) {
112+
this.beanFactory = (beanFactory instanceof ListableBeanFactory ? (ListableBeanFactory) beanFactory : null);
113+
}
114+
115+
/**
116+
* @deprecated as of Spring 4.1, in favor of {@link #setBeanFactory}
117+
*/
118+
@Deprecated
100119
public void setApplicationContext(ApplicationContext applicationContext) {
101-
this.applicationContext = applicationContext;
120+
this.beanFactory = applicationContext;
102121
}
103122

123+
104124
@Override
105-
public int getOrder() {
106-
return LOWEST_PRECEDENCE;
125+
public void afterSingletonsInstantiated() {
126+
if (this.scheduler != null) {
127+
this.registrar.setScheduler(this.scheduler);
128+
}
129+
130+
if (this.beanFactory != null) {
131+
Map<String, SchedulingConfigurer> configurers = this.beanFactory.getBeansOfType(SchedulingConfigurer.class);
132+
for (SchedulingConfigurer configurer : configurers.values()) {
133+
configurer.configureTasks(this.registrar);
134+
}
135+
}
136+
137+
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
138+
Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
139+
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
140+
schedulers.putAll(this.beanFactory.getBeansOfType(TaskScheduler.class));
141+
schedulers.putAll(this.beanFactory.getBeansOfType(ScheduledExecutorService.class));
142+
if (schedulers.size() == 0) {
143+
// do nothing -> fall back to default scheduler
144+
}
145+
else if (schedulers.size() == 1) {
146+
this.registrar.setScheduler(schedulers.values().iterator().next());
147+
}
148+
else if (schedulers.size() >= 2){
149+
throw new IllegalStateException(
150+
"More than one TaskScheduler and/or ScheduledExecutorService " +
151+
"exist within the context. Remove all but one of the beans; or " +
152+
"implement the SchedulingConfigurer interface and call " +
153+
"ScheduledTaskRegistrar#setScheduler explicitly within the " +
154+
"configureTasks() callback. Found the following beans: " + schedulers.keySet());
155+
}
156+
}
157+
158+
this.registrar.afterPropertiesSet();
107159
}
108160

161+
109162
@Override
110163
public Object postProcessBeforeInitialization(Object bean, String beanName) {
111164
return bean;
@@ -254,44 +307,6 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
254307
}
255308
}
256309

257-
@Override
258-
public void onApplicationEvent(ContextRefreshedEvent event) {
259-
if (event.getApplicationContext() != this.applicationContext) {
260-
return;
261-
}
262-
263-
if (this.scheduler != null) {
264-
this.registrar.setScheduler(this.scheduler);
265-
}
266-
267-
Map<String, SchedulingConfigurer> configurers =
268-
this.applicationContext.getBeansOfType(SchedulingConfigurer.class);
269-
for (SchedulingConfigurer configurer : configurers.values()) {
270-
configurer.configureTasks(this.registrar);
271-
}
272-
273-
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
274-
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
275-
schedulers.putAll(this.applicationContext.getBeansOfType(TaskScheduler.class));
276-
schedulers.putAll(this.applicationContext.getBeansOfType(ScheduledExecutorService.class));
277-
if (schedulers.size() == 0) {
278-
// do nothing -> fall back to default scheduler
279-
}
280-
else if (schedulers.size() == 1) {
281-
this.registrar.setScheduler(schedulers.values().iterator().next());
282-
}
283-
else if (schedulers.size() >= 2){
284-
throw new IllegalStateException(
285-
"More than one TaskScheduler and/or ScheduledExecutorService " +
286-
"exist within the context. Remove all but one of the beans; or " +
287-
"implement the SchedulingConfigurer interface and call " +
288-
"ScheduledTaskRegistrar#setScheduler explicitly within the " +
289-
"configureTasks() callback. Found the following beans: " + schedulers.keySet());
290-
}
291-
}
292-
293-
this.registrar.afterPropertiesSet();
294-
}
295310

296311
@Override
297312
public void destroy() {

spring-jms/src/main/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessor.java

Lines changed: 58 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222

2323
import org.springframework.aop.support.AopUtils;
2424
import org.springframework.beans.BeansException;
25+
import org.springframework.beans.factory.BeanFactory;
26+
import org.springframework.beans.factory.BeanFactoryAware;
2527
import org.springframework.beans.factory.BeanInitializationException;
28+
import org.springframework.beans.factory.ListableBeanFactory;
2629
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
30+
import org.springframework.beans.factory.SmartInitializingSingleton;
2731
import org.springframework.beans.factory.config.BeanPostProcessor;
28-
import org.springframework.context.ApplicationContext;
29-
import org.springframework.context.ApplicationContextAware;
30-
import org.springframework.context.ApplicationListener;
3132
import org.springframework.context.annotation.AnnotationConfigUtils;
32-
import org.springframework.context.event.ContextRefreshedEvent;
3333
import org.springframework.core.Ordered;
3434
import org.springframework.core.annotation.AnnotationUtils;
3535
import org.springframework.jms.config.DefaultJmsHandlerMethodFactory;
@@ -39,6 +39,7 @@
3939
import org.springframework.jms.config.JmsListenerEndpointRegistry;
4040
import org.springframework.jms.config.MethodJmsListenerEndpoint;
4141
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
42+
import org.springframework.util.Assert;
4243
import org.springframework.util.ReflectionUtils;
4344
import org.springframework.util.StringUtils;
4445

@@ -60,6 +61,7 @@
6061
* {@link EnableJms} Javadoc for complete usage details.
6162
*
6263
* @author Stephane Nicoll
64+
* @author Juergen Hoeller
6365
* @since 4.1
6466
* @see JmsListener
6567
* @see EnableJms
@@ -69,11 +71,11 @@
6971
* @see org.springframework.jms.config.AbstractJmsListenerEndpoint
7072
* @see MethodJmsListenerEndpoint
7173
*/
72-
public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered,
73-
ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
74+
public class JmsListenerAnnotationBeanPostProcessor
75+
implements BeanPostProcessor, Ordered, BeanFactoryAware, SmartInitializingSingleton {
7476

7577
/**
76-
* The bean name of the default {@link JmsListenerContainerFactory}
78+
* The bean name of the default {@link JmsListenerContainerFactory}.
7779
*/
7880
static final String DEFAULT_JMS_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "jmsListenerContainerFactory";
7981

@@ -82,9 +84,9 @@ public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor
8284

8385
private String containerFactoryBeanName = DEFAULT_JMS_LISTENER_CONTAINER_FACTORY_BEAN_NAME;
8486

85-
private final JmsHandlerMethodFactoryAdapter jmsHandlerMethodFactory = new JmsHandlerMethodFactoryAdapter();
87+
private BeanFactory beanFactory;
8688

87-
private ApplicationContext applicationContext;
89+
private final JmsHandlerMethodFactoryAdapter jmsHandlerMethodFactory = new JmsHandlerMethodFactoryAdapter();
8890

8991
private final JmsListenerEndpointRegistrar registrar = new JmsListenerEndpointRegistrar();
9092

@@ -124,9 +126,50 @@ public void setJmsHandlerMethodFactory(JmsHandlerMethodFactory jmsHandlerMethodF
124126
this.jmsHandlerMethodFactory.setJmsHandlerMethodFactory(jmsHandlerMethodFactory);
125127
}
126128

129+
/**
130+
* Making a {@link BeanFactory} available is optional; if not set,
131+
* {@link JmsListenerConfigurer} beans won't get autodetected and an
132+
* {@link #setEndpointRegistry endpoint registry} has to be explicitly configured.
133+
*/
134+
@Override
135+
public void setBeanFactory(BeanFactory beanFactory) {
136+
this.beanFactory = beanFactory;
137+
}
138+
139+
127140
@Override
128-
public void setApplicationContext(ApplicationContext applicationContext) {
129-
this.applicationContext = applicationContext;
141+
public void afterSingletonsInstantiated() {
142+
this.registrar.setBeanFactory(this.beanFactory);
143+
144+
if (this.beanFactory instanceof ListableBeanFactory) {
145+
Map<String, JmsListenerConfigurer> instances =
146+
((ListableBeanFactory) this.beanFactory).getBeansOfType(JmsListenerConfigurer.class);
147+
for (JmsListenerConfigurer configurer : instances.values()) {
148+
configurer.configureJmsListeners(this.registrar);
149+
}
150+
}
151+
152+
if (this.registrar.getEndpointRegistry() == null) {
153+
if (this.endpointRegistry == null) {
154+
Assert.state(this.beanFactory != null, "BeanFactory must be set to find endpoint registry by bean name");
155+
this.endpointRegistry = this.beanFactory.getBean(
156+
AnnotationConfigUtils.JMS_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME, JmsListenerEndpointRegistry.class);
157+
}
158+
this.registrar.setEndpointRegistry(this.endpointRegistry);
159+
}
160+
161+
if (this.containerFactoryBeanName != null) {
162+
this.registrar.setContainerFactoryBeanName(this.containerFactoryBeanName);
163+
}
164+
165+
// Set the custom handler method factory once resolved by the configurer
166+
JmsHandlerMethodFactory handlerMethodFactory = this.registrar.getJmsHandlerMethodFactory();
167+
if (handlerMethodFactory != null) {
168+
this.jmsHandlerMethodFactory.setJmsHandlerMethodFactory(handlerMethodFactory);
169+
}
170+
171+
// Actually register all listeners
172+
this.registrar.afterPropertiesSet();
130173
}
131174

132175

@@ -189,8 +232,9 @@ protected void processJmsListener(JmsListener jmsListener, Method method, Object
189232
JmsListenerContainerFactory<?> factory = null;
190233
String containerFactoryBeanName = jmsListener.containerFactory();
191234
if (StringUtils.hasText(containerFactoryBeanName)) {
235+
Assert.state(this.beanFactory != null, "BeanFactory must be set to obtain container factory by bean name");
192236
try {
193-
factory = this.applicationContext.getBean(containerFactoryBeanName, JmsListenerContainerFactory.class);
237+
factory = this.beanFactory.getBean(containerFactoryBeanName, JmsListenerContainerFactory.class);
194238
}
195239
catch (NoSuchBeanDefinitionException ex) {
196240
throw new BeanInitializationException("Could not register jms listener endpoint on [" +
@@ -199,49 +243,7 @@ protected void processJmsListener(JmsListener jmsListener, Method method, Object
199243
}
200244
}
201245

202-
registrar.registerEndpoint(endpoint, factory);
203-
204-
}
205-
206-
@Override
207-
public void onApplicationEvent(ContextRefreshedEvent event) {
208-
if (event.getApplicationContext() != this.applicationContext) {
209-
return;
210-
}
211-
212-
Map<String, JmsListenerConfigurer> instances =
213-
this.applicationContext.getBeansOfType(JmsListenerConfigurer.class);
214-
for (JmsListenerConfigurer configurer : instances.values()) {
215-
configurer.configureJmsListeners(registrar);
216-
}
217-
218-
this.registrar.setApplicationContext(this.applicationContext);
219-
220-
if (this.registrar.getEndpointRegistry() == null) {
221-
if (this.endpointRegistry == null) {
222-
this.endpointRegistry = this.applicationContext.getBean(
223-
AnnotationConfigUtils.JMS_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME, JmsListenerEndpointRegistry.class);
224-
}
225-
this.registrar.setEndpointRegistry(this.endpointRegistry);
226-
}
227-
228-
if (this.containerFactoryBeanName != null) {
229-
this.registrar.setContainerFactoryBeanName(this.containerFactoryBeanName);
230-
}
231-
232-
// Set the custom handler method factory once resolved by the configurer
233-
JmsHandlerMethodFactory handlerMethodFactory = registrar.getJmsHandlerMethodFactory();
234-
if (handlerMethodFactory != null) {
235-
this.jmsHandlerMethodFactory.setJmsHandlerMethodFactory(handlerMethodFactory);
236-
}
237-
238-
// Create all the listeners and starts them
239-
try {
240-
this.registrar.afterPropertiesSet();
241-
}
242-
catch (Exception ex) {
243-
throw new BeanInitializationException("Failed to initialize JmsListenerEndpointRegistrar", ex);
244-
}
246+
this.registrar.registerEndpoint(endpoint, factory);
245247
}
246248

247249
private String getEndpointId(JmsListener jmsListener) {
@@ -282,7 +284,7 @@ private JmsHandlerMethodFactory getJmsHandlerMethodFactory() {
282284

283285
private JmsHandlerMethodFactory createDefaultJmsHandlerMethodFactory() {
284286
DefaultJmsHandlerMethodFactory defaultFactory = new DefaultJmsHandlerMethodFactory();
285-
defaultFactory.setApplicationContext(applicationContext);
287+
defaultFactory.setBeanFactory(beanFactory);
286288
defaultFactory.afterPropertiesSet();
287289
return defaultFactory;
288290
}

0 commit comments

Comments
 (0)