diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java
index 7f366d56029..47181986bf0 100644
--- a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java
+++ b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -90,7 +90,7 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSu
return proxyFactory.getProxy(getProxyClassLoader());
}
- // No async proxy needed.
+ // No proxy needed.
return bean;
}
@@ -155,7 +155,7 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSu
* Subclasses may choose to implement this: for example,
* to change the interfaces exposed.
*
The default implementation is empty.
- * @param proxyFactory ProxyFactory that is already configured with
+ * @param proxyFactory the ProxyFactory that is already configured with
* target, advisor and interfaces and will be used to create the proxy
* immediately after this method returns
* @since 4.2.3
diff --git a/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyFactoryBean.java
index c93d3dfeb32..6c983d2a666 100644
--- a/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyFactoryBean.java
+++ b/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,7 +50,8 @@ import org.springframework.util.ClassUtils;
* @see #setProxyTargetClass
*/
@SuppressWarnings("serial")
-public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean, BeanFactoryAware {
+public class ScopedProxyFactoryBean extends ProxyConfig
+ implements FactoryBean, BeanFactoryAware, AopInfrastructureBean {
/** The TargetSource that manages scoping */
private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();
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 04ad5180c4d..3fbca70456f 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
@@ -32,6 +32,7 @@ import java.util.concurrent.ScheduledExecutorService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
@@ -306,7 +307,12 @@ public class ScheduledAnnotationBeanPostProcessor
}
@Override
- public Object postProcessAfterInitialization(final Object bean, String beanName) {
+ public Object postProcessAfterInitialization(Object bean, String beanName) {
+ if (bean instanceof AopInfrastructureBean) {
+ // Ignore AOP infrastructure such as scoped proxies.
+ return bean;
+ }
+
Class> targetClass = AopProxyUtils.ultimateTargetClass(bean);
if (!this.nonAnnotatedClasses.contains(targetClass)) {
Map> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
@@ -341,6 +347,12 @@ public class ScheduledAnnotationBeanPostProcessor
return bean;
}
+ /**
+ * Process the given {@code @Scheduled} method declaration on the given bean.
+ * @param scheduled the @Scheduled annotation
+ * @param method the method that the annotation has been declared on
+ * @param bean the target bean instance
+ */
protected void processScheduled(Scheduled scheduled, Method method, Object bean) {
try {
Assert.isTrue(method.getParameterTypes().length == 0,
diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java
index 4cbdbb7305f..63d674818b7 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,8 +27,6 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
-import org.springframework.scheduling.Trigger;
-import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.IntervalTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@@ -447,19 +445,8 @@ public class EnableSchedulingTests {
public TaskScheduler scheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.initialize();
- scheduler.schedule(
- new Runnable() {
- @Override
- public void run() {
- counter().incrementAndGet();
- }
- },
- new Trigger() {
- @Override
- public Date nextExecutionTime(TriggerContext triggerContext) {
- return new Date(new Date().getTime()+10);
- }
- });
+ scheduler.schedule(() -> counter().incrementAndGet(),
+ triggerContext -> new Date(new Date().getTime()+10));
return scheduler;
}
}
diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
index 9b262718b63..ae36f5ca08d 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
@@ -34,11 +34,15 @@ import org.junit.After;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.annotation.AliasFor;
import org.springframework.scheduling.Trigger;
@@ -49,8 +53,7 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
import org.springframework.scheduling.support.SimpleTriggerContext;
-import org.springframework.tests.Assume;
-import org.springframework.tests.TestGroup;
+import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
@@ -222,9 +225,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
@Test
- public void cronTask() throws InterruptedException {
- Assume.group(TestGroup.LONG_RUNNING);
-
+ public void cronTask() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -246,13 +247,10 @@ public class ScheduledAnnotationBeanPostProcessorTests {
assertEquals(target, targetObject);
assertEquals("cron", targetMethod.getName());
assertEquals("*/7 * * * * ?", task.getExpression());
- Thread.sleep(10000);
}
@Test
- public void cronTaskWithZone() throws InterruptedException {
- Assume.group(TestGroup.LONG_RUNNING);
-
+ public void cronTaskWithZone() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(CronWithTimezoneTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
@@ -280,34 +278,30 @@ public class ScheduledAnnotationBeanPostProcessorTests {
CronTrigger cronTrigger = (CronTrigger) trigger;
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+10"));
cal.clear();
- cal.set(2013, 3, 15, 4, 0); // 15-04-2013 4:00 GMT+10
+ cal.set(2013, 3, 15, 4, 0); // 15-04-2013 4:00 GMT+10
Date lastScheduledExecutionTime = cal.getTime();
Date lastActualExecutionTime = cal.getTime();
- cal.add(Calendar.MINUTE, 30); // 4:30
+ cal.add(Calendar.MINUTE, 30); // 4:30
Date lastCompletionTime = cal.getTime();
TriggerContext triggerContext = new SimpleTriggerContext(
lastScheduledExecutionTime, lastActualExecutionTime, lastCompletionTime);
cal.add(Calendar.MINUTE, 30);
- cal.add(Calendar.HOUR_OF_DAY, 1); // 6:00
+ cal.add(Calendar.HOUR_OF_DAY, 1); // 6:00
Date nextExecutionTime = cronTrigger.nextExecutionTime(triggerContext);
- assertEquals(cal.getTime(), nextExecutionTime); // assert that 6:00 is next execution time
- Thread.sleep(10000);
+ assertEquals(cal.getTime(), nextExecutionTime); // assert that 6:00 is next execution time
}
@Test(expected = BeanCreationException.class)
- public void cronTaskWithInvalidZone() throws InterruptedException {
- Assume.group(TestGroup.LONG_RUNNING);
-
+ public void cronTaskWithInvalidZone() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(CronWithInvalidTimezoneTestBean.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
- Thread.sleep(10000);
}
@Test(expected = BeanCreationException.class)
- public void cronTaskWithMethodValidation() throws InterruptedException {
+ public void cronTaskWithMethodValidation() {
BeanDefinition validationDefinition = new RootBeanDefinition(MethodValidationPostProcessor.class);
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class);
@@ -317,6 +311,29 @@ public class ScheduledAnnotationBeanPostProcessorTests {
context.refresh();
}
+ @Test
+ public void cronTaskWithScopedProxy() {
+ BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
+ context.registerBeanDefinition("postProcessor", processorDefinition);
+ new AnnotatedBeanDefinitionReader(context).register(ProxiedCronTestBean.class, ProxiedCronTestBeanDependent.class);
+ context.refresh();
+
+ Object postProcessor = context.getBean("postProcessor");
+ ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
+ new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
+ @SuppressWarnings("unchecked")
+ List cronTasks = (List)
+ new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
+ assertEquals(1, cronTasks.size());
+ CronTask task = cronTasks.get(0);
+ ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
+ Object targetObject = runnable.getTarget();
+ Method targetMethod = runnable.getMethod();
+ assertEquals(context.getBean(ScopedProxyUtils.getTargetBeanName("target")), targetObject);
+ assertEquals("cron", targetMethod.getName());
+ assertEquals("*/7 * * * * ?", task.getExpression());
+ }
+
@Test
public void metaAnnotationWithFixedRate() {
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
@@ -352,11 +369,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
Object postProcessor = context.getBean("postProcessor");
Object target = context.getBean("target");
- ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(
- postProcessor).getPropertyValue("registrar");
+ ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
+ new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
@SuppressWarnings("unchecked")
- List fixedRateTasks = (List) new DirectFieldAccessor(registrar).getPropertyValue(
- "fixedRateTasks");
+ List fixedRateTasks = (List)
+ new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
assertEquals(1, fixedRateTasks.size());
IntervalTask task = fixedRateTasks.get(0);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
@@ -627,8 +644,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
static class SeveralFixedRatesWithSchedulesContainerAnnotationTestBean {
- @Schedules({ @Scheduled(fixedRate = 4000),
- @Scheduled(fixedRate = 4000, initialDelay = 2000) })
+ @Schedules({@Scheduled(fixedRate = 4000), @Scheduled(fixedRate = 4000, initialDelay = 2000)})
public void fixedRate() {
}
}
@@ -705,6 +721,24 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
+ @Component("target")
+ @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
+ static class ProxiedCronTestBean {
+
+ @Scheduled(cron = "*/7 * * * * ?")
+ public void cron() throws IOException {
+ throw new IOException("no no no");
+ }
+ }
+
+
+ static class ProxiedCronTestBeanDependent {
+
+ public ProxiedCronTestBeanDependent(ProxiedCronTestBean testBean) {
+ }
+ }
+
+
static class NonVoidReturnTypeTestBean {
@Scheduled(cron = "0 0 9-17 * * MON-FRI")
@@ -785,6 +819,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
}
+
static class PropertyPlaceholderWithCronTestBean {
@Scheduled(cron = "${schedules.businessHours}")