admin管理员组文章数量:1794759
spring定时任务详解spring schedule和spring
从实现的技术上来分类,java定时任务目前主要有三种:
综上,spring中使用定时任务有两种方式:spring schedule和spring-quartz,接下来我们重点介绍这两种。使用前都需要引入spring的包。
<!-- spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework.version}</version> </dependency> spring schedule1、xml配置的方式:
1)application.xml:
首先在application.xml中引入task的命名空间,以及通过task标签定义任务。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xmlns:task="www.springframework/schema/task" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans-4.0.xsd www.springframework/schema/task www.springframework/schema/task/spring-task-4.0.xsd"> <task:scheduler id="myScheduler"/> <task:scheduled-tasks scheduler="myScheduler"> <task:scheduled ref="doSomethingTask" method="doSomething" cron="0 * * * * *"/> </task:scheduled-tasks> </beans>2)任务类:
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class DoSomethingTask { public void doSomething() { System.out.println("do something"); } }2、@schedule 注解方式:
1)application.xml
同样在application.xml中引入task的命名空间,以及启用注解驱动的定时任务。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xmlns:task="www.springframework/schema/task" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans-4.0.xsd www.springframework/schema/task www.springframework/schema/task/spring-task-4.0.xsd"> <task:annotation-driven/> </beans>2)任务类:
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class DoSomethingTask { @Scheduled(cron="0 * * * * *") public void doSomething() { System.out.println("do something"); } }3、Cron表达式:
由6~7项组成,中间用空格分开。从左到右依次是:秒、分、时、日、月、周几、年(可省略)。值可以是数字,也可以是以下符号: *:所有值都匹配 ?:无所谓,不关心,通常放在“周几”里 ,:或者 /:增量值 -:区间
例如:
0 * * * * *:每分钟(当秒为0的时候) 0 0 * * * *:每小时(当秒和分都为0的时候) */10 * * * * *:每10秒 0 5/15 * * * *:每小时的5分、20分、35分、50分 0 0 9,13 * * *:每天的9点和13点4、@Scheduled注解的另外两个属性:fixedRate和fixedDelay
1)fixedDelay设置的是:上一个任务结束后多久执行下一个任务;
2)fixedRate设置的是:上一个任务的开始到下一个任务开始时间的间隔;
注:如果是强调任务间隔的定时任务,建议使用fixedRate和fixedDelay,如果是强调任务在某时某分某刻执行的定时任务,建议使用cron表达式。
5、并发执行
1)spring schedule的定时任务默认是单线程的
处理方式是等待上一个任务执行完成后,再去执行下一个任务。(无论是cron还是fixedDelay、fixedRate都遵循这个原则)。下面举一些例子:
示例1:通过cron定时执行:任务运行时间6s、每5s运行一次任务
//使用注解方式创建定时任务 <task:annotation-driven/> @Component public class testTask { private Logger logger = LoggerFactory.getLogger(testTask.class); @Scheduled(cron = "0/5 * * * * ?") public void doTask() { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(6*1_000); logger.info(Thread.currentThread().getName()+"===task end"); } } //日志如下 2018-06-11 16:03:00.006 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:03:06.013 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end 2018-06-11 16:03:10.115 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:03:17.267 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end 2018-06-11 16:03:20.055 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:03:26.164 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end根据日志可以看出,spring schedule默认是单线程处理的,下一个任务会等上一个运行完再执行。
示例2:换成fixedDelay
@Scheduled(fixedDelay = 5*1_000) public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(6*1_000); logger.info(Thread.currentThread().getName()+"===task end"); } //日志如下: 2018-06-11 16:31:08.122 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:31:14.139 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end 2018-06-11 16:31:19.149 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:31:25.261 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end 2018-06-11 16:31:30.269 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:31:36.385 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end从日志可以看出,任务结束时间再经过5s开始再次运行。
示例3:fixedRate
@Scheduled(fixedRate = 5*1_000) public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(6*1_000); logger.info(Thread.currentThread().getName()+"===task end"); } //日志 2018-06-11 16:54:36.118 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:54:42.580 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end 2018-06-11 16:54:42.607 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:54:48.632 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end 2018-06-11 16:54:48.639 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 16:54:55.188 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end从日志可以看出,上一个任务结束后,下一个任务立刻开始执行了,因为:fixedRate设置的上一个任务的开始时间到下一个任务开始时间的间隔。
示例4:fixedRate
上面例子,运行时间从6s改成2s,日志如下:
2018-06-11 17:08:43.086 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 17:08:45.093 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end 2018-06-11 17:08:48.025 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 17:08:50.083 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end 2018-06-11 17:08:53.239 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task run 2018-06-11 17:08:55.245 [pool-12-thread-1] INFO service.task.testTask -pool-12-thread-1===task end结果和我们推断的一致,两个任务的开始时间间隔是5s。
2)配置并行处理
上面的例子是同一个task,如果前一个还没跑完后面一个就不会触发,这没有太大问题。但是,假设系统中有多个task,默认spring schedule是单线程的,就会造成不同的task也不能同时运行,就不太合理了。解决方法:
方法一:配置多个线程,但这样会导致同一个task前一个还没跑完后面又被触发的问题。
<task:scheduler id="scheduler" pool-size="2" />方法二:让任务分别运行在不同的scheduler里
<task:scheduler id="myScheduler1"/> <task:scheduler id="myScheduler2"/> <task:scheduled-tasks scheduler="myScheduler1"> <task:scheduled ref="doSomethingTask" method="doSomething" cron="${0 * * * * *}"/> </task:scheduled-tasks> <task:scheduled-tasks scheduler="myScheduler2"> <task:scheduled ref="doOtherThingTask" method="doOtherThing" cron="${0 * * * * *}"/> </task:scheduled-tasks> spring-quartzmaven中需要引入:quartz.jar、spring-context-support.jar。
示例:
1)定义任务类:(spring集成的quartz不需要集成任何类)
@Service public class QuartzTest { public void test(){ System.out.println("It's time to run :" + new Date().toString()); //TODO 执行任务逻辑 //........ } }2)spring-quartz.xml配置:
a)SimpleTrigger方式:
<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref local="quartzTestTrigger" /> </list> </property> </bean> <bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="quartzTestJob"/> <!-- 20秒后运行 --> <property name="startDelay" value="20000" /> <!-- 每隔三十秒重复 --> <property name="repeatInterval" value="30000" /> </bean> <bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="quartzTest"></property> <property name="targetMethod" value="autoRun"></property> <property name="concurrent" value="false"></property><!--不并发运行--> </bean>b)CronTrigger方式:
<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref local="quartzTestTrigger" /> </list> </property> <property name="startupDelay" value="500"/> </bean> <bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="quartzTestJob"/> <property name="cronExpression"> <value>0 */1 * * * ?</value> </property> </bean> <bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="quartzTest"></property> <property name="targetMethod" value="autoRun"></property> <property name="concurrent" value="false"></property><!--不并发运行--> </bean>最后,在spring主配置文件application.xml中把上面的application-quartz.xml 包含进去即可。
版权声明:本文标题:spring定时任务详解spring schedule和spring 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686479693a72175.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论