提交 4d5fe57a 编写于 作者: C Chris Beams

Polish scheduled task execution infrastructure

In anticipation of substantive changes required to implement "initial
delay" support in the <task:scheduled> element and @Scheduled
annotation, the following updates have been made to the components and
infrastructure supporting scheduled task execution:

 - Fix code style violations
 - Fix compiler warnings
 - Add Javadoc where missing, update to use {@code} tags, etc.
 - Organize imports to follow conventions
上级 e2fbaa84
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
......@@ -24,11 +24,11 @@ import java.lang.annotation.Target;
/**
* Annotation that marks a method to be scheduled. Exactly one of the
* <code>cron</code>, <code>fixedDelay</code>, or <code>fixedRate</code>
* attributes must be provided.
* {@link #cron()}, {@link #fixedDelay()}, or {@link #fixedRate()}
* attributes must be specified.
*
* <p>The annotated method must expect no arguments and have a
* <code>void</code> return type.
* {@code void} return type.
*
* <p>Processing of {@code @Scheduled} annotations is performed by
* registering a {@link ScheduledAnnotationBeanPostProcessor}. This can be
......@@ -49,9 +49,10 @@ public @interface Scheduled {
/**
* A cron-like expression, extending the usual UN*X definition to include
* triggers on the second as well as minute, hour, day of month, month
* and day of week. e.g. <code>"0 * * * * MON-FRI"</code> means once
* per minute on weekdays (at the top of the minute - the 0th second).
* and day of week. e.g. {@code "0 * * * * MON-FRI"} means once per minute on
* weekdays (at the top of the minute - the 0th second).
* @return an expression that can be parsed to a cron schedule
* @see org.springframework.scheduling.support.CronSequenceGenerator
*/
String cron() default "";
......
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
......@@ -17,6 +17,7 @@
package org.springframework.scheduling.annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
......@@ -104,7 +105,6 @@ public class ScheduledAnnotationBeanPostProcessor
return LOWEST_PRECEDENCE;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
......@@ -124,9 +124,11 @@ public class ScheduledAnnotationBeanPostProcessor
// found a @Scheduled method on the target class for this JDK proxy -> is it
// also present on the proxy itself?
method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
} catch (SecurityException ex) {
}
catch (SecurityException ex) {
ReflectionUtils.handleReflectionException(ex);
} catch (NoSuchMethodException ex) {
}
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 " +
......@@ -137,7 +139,7 @@ public class ScheduledAnnotationBeanPostProcessor
}
Runnable runnable = new ScheduledMethodRunnable(bean, method);
boolean processedSchedule = false;
String errorMessage = "Exactly one of 'cron', 'fixedDelay', or 'fixedRate' is required.";
String errorMessage = "Exactly one of the 'cron', 'fixedDelay', or 'fixedRate' attributes is required.";
String cron = annotation.cron();
if (!"".equals(cron)) {
processedSchedule = true;
......@@ -170,7 +172,8 @@ public class ScheduledAnnotationBeanPostProcessor
return;
}
Map<String, SchedulingConfigurer> configurers = applicationContext.getBeansOfType(SchedulingConfigurer.class);
Map<String, SchedulingConfigurer> configurers =
this.applicationContext.getBeansOfType(SchedulingConfigurer.class);
if (this.cronTasks.isEmpty() && this.fixedDelayTasks.isEmpty() &&
this.fixedRateTasks.isEmpty() && configurers.isEmpty()) {
......@@ -190,19 +193,23 @@ public class ScheduledAnnotationBeanPostProcessor
configurer.configureTasks(this.registrar);
}
if (registrar.getScheduler() == null) {
if (this.registrar.getScheduler() == null) {
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
schedulers.putAll(applicationContext.getBeansOfType(TaskScheduler.class));
schedulers.putAll(applicationContext.getBeansOfType(ScheduledExecutorService.class));
if (schedulers.size() == 0) {
// do nothing -> fall back to default scheduler
} else if (schedulers.size() == 1) {
}
else if (schedulers.size() == 1) {
this.registrar.setScheduler(schedulers.values().iterator().next());
} else if (schedulers.size() >= 2){
throw new IllegalStateException("More than one TaskScheduler and/or ScheduledExecutorService " +
"exist within the context. Remove all but one of the beans; or implement the " +
"SchedulingConfigurer interface and call ScheduledTaskRegistrar#setScheduler " +
"explicitly within the configureTasks() callback. Found the following beans: " + schedulers.keySet());
}
else if (schedulers.size() >= 2){
throw new IllegalStateException(
"More than one TaskScheduler and/or ScheduledExecutorService " +
"exist within the context. Remove all but one of the beans; or " +
"implement the SchedulingConfigurer interface and call " +
"ScheduledTaskRegistrar#setScheduler explicitly within the " +
"configureTasks() callback. Found the following beans: " + schedulers.keySet());
}
}
......
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
......@@ -19,12 +19,15 @@ package org.springframework.scheduling.annotation;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
/**
* Interface to be implemented by @{@link org.springframework.context.annotation.Configuration}
* classes annotated with @{@link EnableScheduling} that wish to register scheduled tasks
* in a <em>programmatic</em> fashion as opposed to the <em>declarative</em> approach of
* using the @{@link Scheduled} annotation. For example, this may be necessary when
* implementing {@link org.springframework.scheduling.Trigger Trigger}-based tasks, which
* are not supported by the {@code @Scheduled} annotation.
* Optional interface to be implemented by @{@link
* org.springframework.context.annotation.Configuration Configuration} classes annotated
* with @{@link EnableScheduling}. Typically used for setting a specific
* {@link org.springframework.scheduling.TaskScheduler TaskScheduler} bean to be used when
* executing scheduled tasks or for registering scheduled tasks in a <em>programmatic</em>
* fashion as opposed to the <em>declarative</em> approach of using the @{@link Scheduled}
* annotation. For example, this may be necessary when implementing {@link
* org.springframework.scheduling.Trigger Trigger}-based tasks, which are not supported by
* the {@code @Scheduled} annotation.
*
* <p>See @{@link EnableScheduling} for detailed usage examples.
*
......
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
......@@ -65,7 +65,7 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
/**
* Set the TaskScheduler to register scheduled tasks with.
* Set the {@link TaskScheduler} to register scheduled tasks with.
*/
public void setTaskScheduler(TaskScheduler taskScheduler) {
Assert.notNull(taskScheduler, "TaskScheduler must not be null");
......@@ -73,9 +73,9 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
/**
* Set the {@link org.springframework.scheduling.TaskScheduler} to register scheduled
* tasks with, or a {@link java.util.concurrent.ScheduledExecutorService} to be
* wrapped as a TaskScheduler.
* Set the {@link TaskScheduler} to register scheduled tasks with, or a
* {@link java.util.concurrent.ScheduledExecutorService} to be wrapped as a
* {@code TaskScheduler}.
*/
public void setScheduler(Object scheduler) {
Assert.notNull(scheduler, "Scheduler object must not be null");
......@@ -91,7 +91,7 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
/**
* Return the scheduler instance for this registrar (may be null)
* Return the {@link TaskScheduler} instance for this registrar (may be {@code null}).
*/
public TaskScheduler getScheduler() {
return this.taskScheduler;
......@@ -121,6 +121,14 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
this.fixedRateTasks = fixedRateTasks;
}
/**
* Specify triggered tasks as a Map of Runnables (the tasks) and fixed-delay values.
* @see TaskScheduler#scheduleWithFixedDelay(Runnable, long)
*/
public void setFixedDelayTasks(Map<Runnable, Long> fixedDelayTasks) {
this.fixedDelayTasks = fixedDelayTasks;
}
/**
* Add a Runnable task to be triggered per the given {@link Trigger}.
* @see TaskScheduler#scheduleAtFixedRate(Runnable, long)
......@@ -142,17 +150,6 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
this.cronTasks.put(task, cronExpression);
}
/**
* Add a Runnable task to be triggered with the given fixed delay.
* @see TaskScheduler#scheduleWithFixedDelay(Runnable, long)
*/
public void addFixedDelayTask(Runnable task, long delay) {
if (this.fixedDelayTasks == null) {
this.fixedDelayTasks = new HashMap<Runnable, Long>();
}
this.fixedDelayTasks.put(task, delay);
}
/**
* Add a Runnable task to be triggered at the given fixed-rate period.
* @see TaskScheduler#scheduleAtFixedRate(Runnable, long)
......@@ -165,14 +162,20 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
/**
* Specify triggered tasks as a Map of Runnables (the tasks) and fixed-delay values.
* Add a Runnable task to be triggered with the given fixed delay.
* @see TaskScheduler#scheduleWithFixedDelay(Runnable, long)
*/
public void setFixedDelayTasks(Map<Runnable, Long> fixedDelayTasks) {
this.fixedDelayTasks = fixedDelayTasks;
public void addFixedDelayTask(Runnable task, long delay) {
if (this.fixedDelayTasks == null) {
this.fixedDelayTasks = new HashMap<Runnable, Long>();
}
this.fixedDelayTasks.put(task, delay);
}
/**
* Schedule all registered tasks against the underlying {@linkplain
* #setTaskScheduler(TaskScheduler) task scheduler.
*/
public void afterPropertiesSet() {
if (this.taskScheduler == null) {
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
......@@ -200,7 +203,6 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
}
public void destroy() {
for (ScheduledFuture<?> future : this.scheduledFutures) {
future.cancel(true);
......
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
......@@ -16,10 +16,6 @@
package org.springframework.scheduling.config;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
......@@ -28,6 +24,10 @@ import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Parser for the 'scheduled-tasks' element of the scheduling namespace.
*
......@@ -87,9 +87,8 @@ public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefini
if (!(hasCronAttribute | hasFixedDelayAttribute | hasFixedRateAttribute | hasTriggerAttribute)) {
parserContext.getReaderContext().error(
"exactly one of the 'cron', 'fixed-delay', 'fixed-rate', or 'trigger' attributes is required", taskElement);
// Continue with the possible next task element
continue;
"one of the 'cron', 'fixed-delay', 'fixed-rate', or 'trigger' attributes is required", taskElement);
continue; // with the possible next task element
}
if (hasCronAttribute) {
......
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
......@@ -16,15 +16,11 @@
package org.springframework.scheduling.annotation;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -34,6 +30,10 @@ import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* Tests use of @EnableScheduling on @Configuration classes.
*
......
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
......@@ -25,7 +25,6 @@ import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
......@@ -37,6 +36,8 @@ import org.springframework.context.support.StaticApplicationContext;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
import static org.junit.Assert.*;
/**
* @author Mark Fisher
* @author Juergen Hoeller
......@@ -269,7 +270,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
public static class FixedDelayTestBean {
static class FixedDelayTestBean {
@Scheduled(fixedDelay=5000)
public void fixedDelay() {
......@@ -277,7 +278,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
public static class FixedRateTestBean {
static class FixedRateTestBean {
@Scheduled(fixedRate=3000)
public void fixedRate() {
......@@ -285,7 +286,15 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
public static class CronTestBean {
static class FixedRateWithInitialDelayTestBean {
@Scheduled(initialDelay=1000, fixedRate=3000)
public void fixedRate() {
}
}
static class CronTestBean {
@Scheduled(cron="*/7 * * * * ?")
public void cron() throws IOException {
......@@ -295,7 +304,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
private static class EmptyAnnotationTestBean {
static class EmptyAnnotationTestBean {
@Scheduled
public void invalid() {
......@@ -304,7 +313,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
private static class InvalidCronTestBean {
static class InvalidCronTestBean {
@Scheduled(cron="abc")
public void invalid() {
......@@ -313,7 +322,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
private static class NonVoidReturnTypeTestBean {
static class NonVoidReturnTypeTestBean {
@Scheduled(fixedRate=3000)
public String invalid() {
......@@ -323,7 +332,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
private static class NonEmptyParamListTestBean {
static class NonEmptyParamListTestBean {
@Scheduled(fixedRate=3000)
public void invalid(String oops) {
......@@ -344,7 +353,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
private static @interface Hourly {}
private static class MetaAnnotationFixedRateTestBean {
static class MetaAnnotationFixedRateTestBean {
@EveryFiveSeconds
public void checkForUpdates() {
......@@ -352,7 +361,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
private static class MetaAnnotationCronTestBean {
static class MetaAnnotationCronTestBean {
@Hourly
public void generateReport() {
......@@ -360,7 +369,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
private static class PropertyPlaceholderTestBean {
static class PropertyPlaceholderTestBean {
@Scheduled(cron = "${schedules.businessHours}")
public void x() {
......@@ -370,11 +379,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
@Scheduled(cron = "${schedules.businessHours}")
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.RUNTIME)
private static @interface BusinessHours {}
private static class PropertyPlaceholderMetaAnnotationTestBean {
static class PropertyPlaceholderMetaAnnotationTestBean {
@BusinessHours
public void y() {
......
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
......@@ -21,7 +21,6 @@ import java.util.Collection;
import java.util.Date;
import java.util.Map;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
......@@ -32,6 +31,8 @@ import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
import static org.junit.Assert.*;
/**
* @author Mark Fisher
*/
......
......@@ -472,7 +472,7 @@ public class TaskExecutorExample {
example.</para>
<programlisting language="xml">&lt;task:scheduled-tasks scheduler="myScheduler"&gt;
&lt;task:scheduled ref="someObject" method="someMethod" fixed-delay="5000"/&gt;
&lt;task:scheduled ref="beanA" method="methodA" fixed-delay="5000"/&gt;
&lt;/task:scheduled-tasks&gt;
&lt;task:scheduler id="myScheduler" pool-size="10"/&gt;</programlisting>
......@@ -480,13 +480,16 @@ public class TaskExecutorExample {
<para>As you can see, the scheduler is referenced by the outer element,
and each individual task includes the configuration of its trigger
metadata. In the preceding example, that metadata defines a periodic
trigger with a fixed delay. It could also be configured with a
"fixed-rate", or for more control, a "cron" attribute could be provided
instead. Here's an example featuring these other options.</para>
trigger with a fixed delay indicating the number of milliseconds to wait
after each task execution has completed. Another option is 'fixed-rate',
indicating how often the method should be executed regardless of how long
any previous execution takes. For more control, a "cron" attribute may be
provided instead. Here is an example demonstrating these other options.
</para>
<programlisting language="xml">&lt;task:scheduled-tasks scheduler="myScheduler"&gt;
&lt;task:scheduled ref="someObject" method="someMethod" fixed-rate="5000"/&gt;
&lt;task:scheduled ref="anotherObject" method="anotherMethod" cron="*/5 * * * * MON-FRI"/&gt;
&lt;task:scheduled ref="beanB" method="methodB" fixed-rate="5000"/&gt;
&lt;task:scheduled ref="beanC" method="methodC" cron="*/5 * * * * MON-FRI"/&gt;
&lt;/task:scheduled-tasks&gt;
&lt;task:scheduler id="myScheduler" pool-size="10"/&gt;</programlisting>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册