引
Spring是一个很优秀的框架,它无缝的集成了Quartz,简单方便的让企业级应用更好的使用Quartz进行任务的调度。
Jar包依赖
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>需要注意一点,与Spring3.1以下版本整合必须使用Quartz 1.x.x。
在Spring中使用Quartz方式:
- 任务类继承QuartzJobBean
- 在配置文件里定义任务类和要执行的方法,类和方法仍然是普通类
- 使用注解的方式
任务类Job
package com.chen.quatrz; import org.springframework.stereotype.Service; @Service(value="springD") public class SpringD { public void one() { System.out.println("spring task D 定时任务"); } }
package com.chen.quatrz; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @Service(value="springC") public class SpringC { /* 字段 允许值 允许的特殊字符 秒 0-59 , - * / 分 0-59 , - * / 小时 0-23 , - * / 日期 1-31 , - * ? / L W C 月份 1-12 或者 JAN-DEC , - * / 星期 1-7 或者 SUN-SAT , - * ? / L C # 年(可选) 留空, 1970-2099 , - * / - 区间 * 通配符 ? 你不想设置那个字段 */ @Scheduled(cron="1/2 * * * * ?") public void one() { System.out.println("spring task C 定时任务"); } }
xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="false"> <context:annotation-config /> <context:component-scan base-package="com.chen.quartz" /> <!-- 定时任务注解扫描--> <task:annotation-driven /> <bean id="springDJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="springD" /> <property name="targetMethod" value="one" /> <!-- 是否并发调度 --> <!-- <property name="concurrent" value="true" /> --> </bean> <!-- 触发器 --> <bean id="springDJobCT" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="springDJob" /> <property name="cronExpression" value="2/5 * * * * ?" /> </bean> <!-- 线程池 --> <bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <!-- 核心线程数 --> <property name="corePoolSize" value="5" /> <!-- 最大线程数 --> <property name="maxPoolSize" value="10" /> <!-- 队列最大长度 >=mainExecutor.maxSize --> <property name="queueCapacity" value="90" /> <!-- 线程池维护线程所允许的空闲时间 --> <property name="keepAliveSeconds" value="3000" /> <!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. --> <property name="rejectedExecutionHandler"> <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" /> </property> </bean> <!-- 调度工厂 --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" > <property name="triggers"> <list> <ref bean="springDJobCT" /> </list> </property> <property name="taskExecutor" ref="executor" /> </bean> <!-- Spring内部有一个task,是Spring自带的一个设定时间自动任务调度 --> <!-- ref是工作类 method是工作类中要执行的方法 initial-delay是任务第一次被调用前的延时,单位毫秒 fixed-delay是上一个调用完成后再次调用的延时 fixed-rate是上一个调用开始后再次调用的延时(不用等待上一次调用完成) cron是表达式,表示在什么时候进行任务调度 --> <!-- <task:scheduled-tasks> <task:scheduled ref="springD" method="one" cron="2/5 * * * * ?"/> </task:scheduled-tasks> --> </beans>
测试
package com.chen.junit; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:spring/quartz-task.xml"}) public class SpringTest { @Test public void one() throws InterruptedException { Thread.sleep(1000000); } }
运行结果
DEBUG 2018-01-19 15:56:45,822 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor: Could not find default TaskScheduler bean org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.scheduling.TaskScheduler] is defined at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:371) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:183) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:162) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:85) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:331) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:773) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483) at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:125) at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60) at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:109) at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:261) at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:68) at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:86) at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:72) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:212) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:200) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:259) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:261) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:219) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) DEBUG 2018-01-19 15:56:45,822 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor: Could not find default ScheduledExecutorService bean org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.scheduling.TaskScheduler] is defined at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:371) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:183) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:162) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:85) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:331) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:773) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483) at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:125) at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60) at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:109) at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:261) at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:68) at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:86) at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:72) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:212) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:200) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:259) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:261) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:219) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) DEBUG 2018-01-19 15:56:45,838 org.springframework.core.env.PropertySourcesPropertyResolver: Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties] DEBUG 2018-01-19 15:56:45,838 org.springframework.core.env.PropertySourcesPropertyResolver: Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment] DEBUG 2018-01-19 15:56:45,838 org.springframework.core.env.PropertySourcesPropertyResolver: Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null] DEBUG 2018-01-19 15:56:45,838 org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate: Storing ApplicationContext in cache under key [[MergedContextConfiguration@5f9d02cb testClass = SpringTest, locations = '{classpath:spring/quartz-task.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]] DEBUG 2018-01-19 15:56:45,838 org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate: Spring test ApplicationContext cache statistics: [ContextCache@5b799640 size = 1, hitCount = 0, missCount = 1, parentContextCount = 0] DEBUG 2018-01-19 15:56:45,838 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor: No @Scheduled annotations found on bean class: class com.chen.junit.SpringTest DEBUG 2018-01-19 15:56:46,821 org.quartz.utils.UpdateChecker: Checking for available updated version of Quartz... spring task C 定时任务 DEBUG 2018-01-19 15:56:47,009 org.quartz.core.QuartzSchedulerThread: batch acquisition of 1 triggers DEBUG 2018-01-19 15:56:47,009 org.quartz.core.JobRunShell: Calling execute on job DEFAULT.springDJob spring task D 定时任务 DEBUG 2018-01-19 15:56:47,321 org.quartz.utils.UpdateChecker: Quartz version update check failed: Server returned HTTP response code: 403 for URL: http://www.terracotta.org/kit/reflector?kitID=quartz&pageID=update.properties&id=-1062717439&os-name=Windows+7&jvm-name=Java+HotSpot%28TM%29+64-Bit+Server+VM&jvm-version=1.8.0_131&platform=amd64&tc-version=2.2.1&tc-product=Quartz&source=Quartz&uptime-secs=1&patch=UNKNOWN spring task C 定时任务 spring task C 定时任务
Spring的定时任务调度器会尝试获取一个注册过的 task scheduler来做任务调度,它会尝试通过BeanFactory.getBean的方法来获取一个注册过的scheduler bean,获取的步骤如下:
1.尝试从配置中找到一个TaskScheduler Bean
2.寻找ScheduledExecutorService Bean
3.使用默认的scheduler
前两步,如果找不到的话,就会以debug的方式抛出异常,分别是:
logger.debug("Could not find default TaskScheduler bean", ex);
logger.debug("Could not find default ScheduledExecutorService bean", ex);
所以,日志中打印出来的两个异常,根本不是什么错误信息,也不会影响定时器的使用,只不过是spring的自己打印的一些信息罢了,不过没搞明白,为什么非要用异常的方式打出来,估计是为了看这清晰点吧。也或者,这里面有一些重要的信息需要提示开发者。
Cron Expressions:
Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:
1、Seconds Minutes Hours DayofMonth Month DayofWeek Year
2、Seconds Minutes Hours DayofMonth Month DayofWeek
例 "0 0 12 ? * WED" 在每星期三下午12:00 执行,
个别子表达式可以包含范围, 例如,在前面的例子里("WED")可以替换成 "MON-FRI", "MON, WED, FRI"甚至"MON-WED,SAT".
每一个字段都有一套可以指定有效值,如
Seconds (秒) :可以用数字0-59 表示,
Minutes(分) :可以用数字0-59 表示,
Hours(时) :可以用数字0-23表示,
Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份
Month(月) :可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
●星号(*):可用在所有字段中,表示对应时间域的每一个时刻,例如,*在分钟字段时,表示“每分钟”;
●问号(?):该字符只在日期和星期字段中使用,虽然我现在不知道它的值是多少,但是它的值是唯一的,通过日期可以推出星期,通过本周是周几也可以推出日期。
●减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;
●逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;
●斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;
●L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值 X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五;
●W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;
●LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;
●井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;
● C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。
1)Cron表达式的格式:秒 分 时 日 月 周 年(可选)。
字段名 允许的值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日 1-31 , - * ? / L W C
月 1-12 or JAN-DEC , - * /
周几 1-7 or SUN-SAT , - * ? / L C #
年 (可选字段) empty, 1970-2099 , - * /
2)Cron表达式范例:
每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天23点执行一次:0 0 23 * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每月最后一天23点执行一次:0 0 23 L * ?
每周星期天凌晨1点实行一次:0 0 1 ? * L
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
参考:
http://blog.csdn.net/oarsman/article/details/52801877