From 473d97350ebec5038e2f88fbf5cf6cfaf4bdbcf4 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 7 Oct 2014 17:26:35 +0200 Subject: [PATCH] Explicitly detect (and log) private @Scheduled methods on CGLIB proxies Issue: SPR-12308 (cherry picked from commit 47ed4d6) --- .../ScheduledAnnotationBeanPostProcessor.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java index 81f2e04681b..a78850faa27 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java @@ -17,6 +17,7 @@ package org.springframework.scheduling.annotation; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; @@ -24,6 +25,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; +import org.apache.commons.logging.LogFactory; + import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.config.BeanPostProcessor; @@ -188,17 +191,27 @@ public class ScheduledAnnotationBeanPostProcessor } catch (NoSuchMethodException ex) { throw new IllegalStateException(String.format( - "@Scheduled method '%s' found on bean target class '%s', " + - "but not found in any interface(s) for bean JDK proxy. Either " + - "pull the method up to an interface or switch to subclass (CGLIB) " + - "proxies by setting proxy-target-class/proxyTargetClass " + - "attribute to 'true'", method.getName(), method.getDeclaringClass().getSimpleName())); + "@Scheduled method '%s' found on bean target class '%s' but not " + + "found in any interface(s) for a dynamic proxy. Either pull the " + + "method up to a declared interface or switch to subclass (CGLIB) " + + "proxies by setting proxy-target-class/proxyTargetClass to 'true'", + method.getName(), method.getDeclaringClass().getSimpleName())); + } + } + else if (AopUtils.isCglibProxy(bean)) { + // Common problem: private methods end up in the proxy instance, not getting delegated. + if (Modifier.isPrivate(method.getModifiers())) { + LogFactory.getLog(ScheduledAnnotationBeanPostProcessor.class).warn(String.format( + "@Scheduled method '%s' found on CGLIB proxy for target class '%s' but cannot " + + "be delegated to target bean. Switch its visibility to package or protected.", + method.getName(), method.getDeclaringClass().getSimpleName())); } } Runnable runnable = new ScheduledMethodRunnable(bean, method); boolean processedSchedule = false; - String errorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required"; + String errorMessage = + "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required"; // Determine initial delay long initialDelay = scheduled.initialDelay();