Spring Task定时任务
1.基于Spring Task的任务调度方法:
Spring框架自带的异步执行(TaskExecutor)和任务调度(TaskScheduler)接口。
Spring Task官方地址:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
以下是task任务调度配置:spring-tasks.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:task="http://www.springframework.org/schema/task" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd 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 default-lazy-init="false"> <context:annotation-config /> <!-- spring扫描注解的配置 --> <context:component-scan base-package="com.ouc.test.task" /> <!--开启这个配置,spring才能识别@Scheduled注解 --> <task:annotation-driven scheduler="testScheduler" mode="proxy"/> <task:scheduler id="testScheduler" pool-size="10"/> </beans>
任务调度具体实现:TestTask.java
package com.ouc.test.task; import java.text.SimpleDateFormat;; import java.util.Calendar; import java.util.Date; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component("TestTask") public class TestTask { //每天凌晨4:40执行 @Scheduled(cron = "0 40 4 * * ?") public void TestTask() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date factInPlaceDate = new Date(); Calendar beforeCd = Calendar.getInstance(); beforeCd.setTime(factInPlaceDate); beforeCd.add(Calendar.MONTH, -1); Date beforeFactDate = beforeCd.getTime(); String beforeMonthDate = sdf.format(beforeFactDate); System.out.println("实际到位日期减一个月:" + beforeMonthDate); Calendar afterCd = Calendar.getInstance(); afterCd.setTime(factInPlaceDate); afterCd.add(Calendar.MONTH, +1); Date afterFactDate = afterCd.getTime(); String afterMonthDate = sdf.format(afterFactDate); System.out.println("实际到位日期加一个月:" + afterMonthDate); } }Spring定时任务cronExpression的值(配置定时时间)格式说明:
(1) 秒(0–59) , - * /(2) 分钟(0–59) , - * /
(3) 小时(0–23) , - * /
(4) 月份中的日期(1–31) , - * ? / L W C
(5) 月份(1–12或JAN–DEC) , - * /
(6) 星期中的日期(1–7或SUN–SAT) , - * ? / L C #
(7) 年份(1970–2099) (可选) 留空 , - * /
表达式意义 :
"0 0 12 * * ?" 每天中午12点触发
"0 30 9 ? * *" 每天上午9:30触发
"0 30 9 * * ? 2008" 2008年的每天上午9:30触发
"0 * 13 * * ?" 在每天下午1点到下午1:59期间的每1分钟触发
"0 0/5 13 * * ?" 在每天下午1点到下午1:55期间的每5分钟触发
"0 0/5 13,18 * * ?" 在每天下午1点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 12 * * ?" 在每天下午1点到下午1:05期间的每1分钟触发
"0 10,50 14 ? 3 WED" 每年三月的星期三的下午2:10和2:50触发
"0 30 10 ? * MON-FRI" 周一至周五的上午10:30触发
"0 30 10 15 * ?" 每月15日上午10:30触发
"0 30 10 L * ?" 每月最后一日的上午10:30触发
"0 30 10 ? * 6L" 每月的最后一个星期五上午10:30触发
"0 30 10 ? * 6L 2006-2008" 2006年至2008年的每月的最后一个星期五上午10:30触发
"0 15 9 ? * 6#3" 每月的第三个星期五上午9:15触发
"0 5 * * * " 每天早上5点触发
"0 */2 * * * " 每两小时触发
"0 23-6/2,7 * * * " 晚上11点到早上6点之间每两个小时,早上7点触发
"0 5 1 * 1-3" 每个月的4号和每个礼拜的礼拜一到礼拜三的早上5点触发
"0 2 1 1 * " 1月1日凌晨2点触发
2.基于定时器Timer的定时任务:
TimerManager.java
package com.ouc.test.main; import java.util.Calendar; import java.util.Date; import java.util.Timer; public class TimerManager { public static void main(String[] args) { // TODO Auto-generated method stub new TimerManager(); } private static final long PERIOD_DAY = 24 * 60 * 60 * 1000; //一天 //private static final long PERIOD_WEEK = 7 * 24 * 60 * 60 * 1000; //一周 public TimerManager(){ Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 18); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); Date date=calendar.getTime(); //第一次执行定时任务的时间 //如果第一次执行定时任务的时间 小于当前的时间 //此时要在 第一次执行定时任务的时间加一天,以便此任务在下个时间点执行。如果不加一天,任务会立即执行。 if (date.before(new Date())) { date = this.addDay(date, 1); } Timer timer = new Timer(); System.out.println(date);//输出开始日期 OrderTask orderTask = new OrderTask(); //安排指定的任务在指定的时间开始进行重复的固定延迟执行。 timer.schedule(orderTask, date, PERIOD_DAY);//订单 } //增加或减少天数 public Date addDay(Date date, int num) { Calendar startDT = Calendar.getInstance(); startDT.setTime(date); startDT.add(Calendar.DAY_OF_MONTH, num); return startDT.getTime(); } }OrderTask.java
package com.ouc.test.main; import java.util.TimerTask; public class OrderTask extends TimerTask { public static void main(String[] args) { // TODO Auto-generated method stub OrderTask orerTask = new OrderTask(); orerTask.run(); } public void run() { getOrderInfo(); } public void getOrderInfo() { System.out.println("正在测试Timer定时任务!"); } }
3.Quartz任务调度框架
4.LTS轻任务调度框架介绍:
• LTS框架概况:
LTS是一个轻任务调度框架,参考hadoop的部分思想。有三种角色, JobClient, JobTracker,TaskTracker。各个节点都是无状态的,可以部署多个,来实现负载均衡,实现更大的负载量, 并且框架具有很好的容错能力。 采用Zookeeper暴露节点信息,master选举。Mongo存储任务队列和任务执行日志, netty做底层通信。
▶ JobClient : 主要负责提交任务, 和接收任务执行反馈结果。
▶ JobTracker : 负责接收并分配任务,任务调度。
▶ TaskTracker: 负责执行任务,执行完反馈给JobTracker。
• 架构图:
• 节点组:
▶ 一个节点组等同于一个集群,同一个节点组中的各个节点是对等的,外界无论连接节点组中的任务一个节点都是可以的。
▶ 每个节点组中都有一个master节点,采用zookeeper进行master选举(master宕机,会自动选举出新的master节点),框架会提供接口API来监听master节点的变化,用户可以自己使用master节点做自己想做的事情。
▶ JobClient和TaskTracker都可以存在多个节点组。譬如JobClient 可以存在多个节点组。譬如:JobClient 节点组为‘QN_WEB’中的一个节点提交提交一个只有节点组为‘QN_TRADE’的TaskTracker 才能执行的任务。
▶ (每个集群中)JobTacker只有一个节点组。
▶ 多个JobClient节点组和多个TaskTracker节点组再加上一个JobTacker节点组, 组成一个大的集群。
• 工作流程:
▶ JobClient提交一个任务给 JobTracker, 这里我提供了两种客户端API, 一种是如果JobTracker 不存在或者提交失败,直接返回提交失败。另一种客户端是重试客户端, 如果提交失败,先存储文件,返回给客户端提交成功的信息,待JobTracker可用的时候,再将任务提交。
▶ JobTracker收到JobClient提交来的任务,先生成一个唯一的JobID。然后将任务储存在Mongo集群中。JobTracker 发现有(任务执行的)可用的TaskTracker节点(组)之后,将优先级最大,最先提交的任务分发给TaskTracker。这里JobTracker会优先分配给比较空闲的TaskTracker节点,达到负载均衡。
▶ TaskTracker收到JobTracker分发来的任务之后,执行。执行完毕之后,再反馈任务执行结果给JobTracker(成功or 失败[失败有失败错误信息]),如果发现JobTacker不可用,那么存储文件,等待TaskTracker可用的时候再反馈。反馈结果的同时,询问 JobTacker有没有新的任务要执行。
▶ JobTacker收到TaskTracker节点的任务结果信息,生成并插入(mongo)任务执行日志。根据任务信息决定要不要反馈给客户端。不需要反馈的直接删除, 需要反馈的(同样JobClient不可用存储文件,等待可用重发)。
▶ JobClient收到任务执行结果,进行自己想要的逻辑处理。
• 特性
▶ 负载均衡:
▷ JobClient和 TaskTracker会随机连接JobTracker节点组中的一个节点,实现JobTracker负载均衡。当连接上后,将一直保持连接这个节点,保持连接通道,知道这个节点不可用,减少每次都重新连接一个节点带来的性能开销。
▷ JobTracker分发任务时,是优先分配给最空间的一个TaskTracker节点,实现TaskTracker节点的负载均衡。
▶ 健壮性:
▷ 当节点组中的一个节点当机之后,自动转到其他节点工作。当整个节点组当机之后,将会采用存储文件的方式,待节点组可用的时候进行重发。
▷ 当执行任务的TaskTracker节点当机之后,JobTracker会将这个TaskTracker上的未完成的任务(死任务),重新分配给节点组中其他节点执行。
▶ 伸缩性:
因为各个节点都是无状态的,可以动态增加机器部署实例, 节点关注者会自动发现。
• 调用示例
安装 zookeeper 和 mongo , 执行 data/mongo目录下的 mongo.md 中的语句见 job-example 这里给出的是java API(设置配置)方式启动,也可以使用配置文件中。
▶ JobTracker端
▶ JobClient端
▶ TaskTracker端