Skip to content

Commit 58b22ce

Browse files
committed
Scheduled/JmsListenerAnnotationBeanPostProcessor avoids needless re-scanning of non-annotated classes
Issue: SPR-12189
1 parent d3ea242 commit 58b22ce

File tree

2 files changed

+82
-22
lines changed

2 files changed

+82
-22
lines changed

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

+45-14
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@
1717
package org.springframework.scheduling.annotation;
1818

1919
import java.lang.reflect.Method;
20+
import java.util.Collections;
2021
import java.util.HashMap;
22+
import java.util.LinkedHashSet;
2123
import java.util.Map;
24+
import java.util.Set;
2225
import java.util.TimeZone;
26+
import java.util.concurrent.ConcurrentHashMap;
2327
import java.util.concurrent.ScheduledExecutorService;
2428

29+
import org.apache.commons.logging.Log;
30+
import org.apache.commons.logging.LogFactory;
31+
2532
import org.springframework.aop.support.AopUtils;
2633
import org.springframework.beans.factory.BeanFactory;
2734
import org.springframework.beans.factory.BeanFactoryAware;
@@ -74,6 +81,8 @@ public class ScheduledAnnotationBeanPostProcessor
7481
implements BeanPostProcessor, Ordered, EmbeddedValueResolverAware, BeanFactoryAware,
7582
SmartInitializingSingleton, DisposableBean {
7683

84+
protected final Log logger = LogFactory.getLog(getClass());
85+
7786
private Object scheduler;
7887

7988
private StringValueResolver embeddedValueResolver;
@@ -82,6 +91,9 @@ public class ScheduledAnnotationBeanPostProcessor
8291

8392
private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();
8493

94+
private final Set<Class<?>> nonAnnotatedClasses =
95+
Collections.newSetFromMap(new ConcurrentHashMap<Class<?>, Boolean>(64));
96+
8597

8698
@Override
8799
public int getOrder() {
@@ -117,7 +129,9 @@ public void setBeanFactory(BeanFactory beanFactory) {
117129
*/
118130
@Deprecated
119131
public void setApplicationContext(ApplicationContext applicationContext) {
120-
this.beanFactory = applicationContext;
132+
if (this.beanFactory == null) {
133+
this.beanFactory = applicationContext;
134+
}
121135
}
122136

123137

@@ -146,12 +160,11 @@ else if (schedulers.size() == 1) {
146160
this.registrar.setScheduler(schedulers.values().iterator().next());
147161
}
148162
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());
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());
155168
}
156169
}
157170

@@ -166,15 +179,33 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) {
166179

167180
@Override
168181
public Object postProcessAfterInitialization(final Object bean, String beanName) {
169-
Class<?> targetClass = AopUtils.getTargetClass(bean);
170-
ReflectionUtils.doWithMethods(targetClass, new MethodCallback() {
171-
@Override
172-
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
173-
for (Scheduled scheduled : AnnotationUtils.getRepeatableAnnotation(method, Schedules.class, Scheduled.class)) {
174-
processScheduled(scheduled, method, bean);
182+
if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
183+
final Set<Method> annotatedMethods = new LinkedHashSet<Method>(1);
184+
Class<?> targetClass = AopUtils.getTargetClass(bean);
185+
ReflectionUtils.doWithMethods(targetClass, new MethodCallback() {
186+
@Override
187+
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
188+
for (Scheduled scheduled :
189+
AnnotationUtils.getRepeatableAnnotation(method, Schedules.class, Scheduled.class)) {
190+
processScheduled(scheduled, method, bean);
191+
annotatedMethods.add(method);
192+
}
193+
}
194+
});
195+
if (annotatedMethods.isEmpty()) {
196+
this.nonAnnotatedClasses.add(bean.getClass());
197+
if (logger.isDebugEnabled()) {
198+
logger.debug("No @Scheduled annotations found on bean class: " + bean.getClass());
199+
}
200+
}
201+
else {
202+
// Non-empty set of methods
203+
if (logger.isDebugEnabled()) {
204+
logger.debug(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName +
205+
"': " + annotatedMethods);
175206
}
176207
}
177-
});
208+
}
178209
return bean;
179210
}
180211

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

+37-8
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,16 @@
1717
package org.springframework.jms.annotation;
1818

1919
import java.lang.reflect.Method;
20+
import java.util.Collections;
21+
import java.util.LinkedHashSet;
2022
import java.util.Map;
23+
import java.util.Set;
24+
import java.util.concurrent.ConcurrentHashMap;
2125
import java.util.concurrent.atomic.AtomicInteger;
2226

27+
import org.apache.commons.logging.Log;
28+
import org.apache.commons.logging.LogFactory;
29+
2330
import org.springframework.aop.support.AopUtils;
2431
import org.springframework.beans.BeansException;
2532
import org.springframework.beans.factory.BeanFactory;
@@ -81,6 +88,8 @@ public class JmsListenerAnnotationBeanPostProcessor
8188
static final String DEFAULT_JMS_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "jmsListenerContainerFactory";
8289

8390

91+
protected final Log logger = LogFactory.getLog(getClass());
92+
8493
private JmsListenerEndpointRegistry endpointRegistry;
8594

8695
private String containerFactoryBeanName = DEFAULT_JMS_LISTENER_CONTAINER_FACTORY_BEAN_NAME;
@@ -93,6 +102,9 @@ public class JmsListenerAnnotationBeanPostProcessor
93102

94103
private final AtomicInteger counter = new AtomicInteger();
95104

105+
private final Set<Class<?>> nonAnnotatedClasses =
106+
Collections.newSetFromMap(new ConcurrentHashMap<Class<?>, Boolean>(64));
107+
96108

97109
@Override
98110
public int getOrder() {
@@ -181,16 +193,33 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro
181193

182194
@Override
183195
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
184-
Class<?> targetClass = AopUtils.getTargetClass(bean);
185-
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
186-
@Override
187-
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
188-
JmsListener jmsListener = AnnotationUtils.getAnnotation(method, JmsListener.class);
189-
if (jmsListener != null) {
190-
processJmsListener(jmsListener, method, bean);
196+
if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
197+
final Set<Method> annotatedMethods = new LinkedHashSet<Method>(1);
198+
Class<?> targetClass = AopUtils.getTargetClass(bean);
199+
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
200+
@Override
201+
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
202+
JmsListener jmsListener = AnnotationUtils.getAnnotation(method, JmsListener.class);
203+
if (jmsListener != null) {
204+
processJmsListener(jmsListener, method, bean);
205+
annotatedMethods.add(method);
206+
}
207+
}
208+
});
209+
if (annotatedMethods.isEmpty()) {
210+
this.nonAnnotatedClasses.add(bean.getClass());
211+
if (logger.isDebugEnabled()) {
212+
logger.debug("No @JmsListener annotations found on bean class: " + bean.getClass());
191213
}
192214
}
193-
});
215+
else {
216+
// Non-empty set of methods
217+
if (logger.isDebugEnabled()) {
218+
logger.debug(annotatedMethods.size() + " @JmsListener methods processed on bean '" + beanName +
219+
"': " + annotatedMethods);
220+
}
221+
}
222+
}
194223
return bean;
195224
}
196225

0 commit comments

Comments
 (0)